From 8ab247f861fbe0279741f49187d48c4f0027c135 Mon Sep 17 00:00:00 2001 From: Aleksey Date: Thu, 27 May 2021 13:55:03 +0300 Subject: [PATCH] Registries, Base blocks with entities --- .../blockentities/BaseBarrelBlockEntity.java | 143 +++++++++++++ .../blockentities/BaseChestBlockEntity.java | 10 + .../blockentities/BaseFurnaceBlockEntity.java | 24 +++ .../blockentities/BaseSignBlockEntity.java | 16 ++ .../java/ru/bclib/blocks/BaseAnvilBlock.java | 8 +- .../java/ru/bclib/blocks/BaseBarrelBlock.java | 133 ++++++++++++ .../java/ru/bclib/blocks/BaseChainBlock.java | 4 +- .../java/ru/bclib/blocks/BaseChestBlock.java | 58 ++++++ .../java/ru/bclib/blocks/BaseDoorBlock.java | 4 +- .../ru/bclib/blocks/BaseFurnaceBlock.java | 105 ++++++++++ .../java/ru/bclib/blocks/BaseLadderBlock.java | 4 +- .../java/ru/bclib/blocks/BaseLeavesBlock.java | 4 +- .../ru/bclib/blocks/BaseMetalBarsBlock.java | 4 +- .../java/ru/bclib/blocks/BasePlantBlock.java | 5 +- .../java/ru/bclib/blocks/BaseSignBlock.java | 196 ++++++++++++++++++ .../ru/bclib/blocks/BaseTrapdoorBlock.java | 4 +- .../ru/bclib/blocks/DoublePlantBlock.java | 4 +- .../ru/bclib/blocks/FeatureSaplingBlock.java | 5 +- .../ru/bclib/blocks/SimpleLeavesBlock.java | 4 +- .../java/ru/bclib/blocks/StalactiteBlock.java | 4 +- .../ru/bclib/blocks/UnderwaterPlantBlock.java | 4 +- .../ru/bclib/blocks/UpDownPlantBlock.java | 4 +- src/main/java/ru/bclib/blocks/VineBlock.java | 4 +- .../render/BaseChestBlockEntityRenderer.java | 180 ++++++++++++++++ .../render/BaseSignBlockEntityRenderer.java | 122 +++++++++++ .../ru/bclib/interfaces/IColorProvider.java | 10 + ...IRenderTypeable.java => IRenderTyped.java} | 5 +- .../ru/bclib/interfaces/ISpetialItem.java | 6 + .../java/ru/bclib/items/BaseArmorItem.java | 49 +++++ .../java/ru/bclib/items/BaseAttribute.java | 9 + .../java/ru/bclib/items/BaseBucketItem.java | 13 ++ .../java/ru/bclib/items/BaseDrinkItem.java | 54 +++++ .../java/ru/bclib/items/BaseSpawnEggItem.java | 24 +++ src/main/java/ru/bclib/items/EndDiscItem.java | 11 + .../ru/bclib/items/ModelProviderItem.java | 18 ++ .../java/ru/bclib/items/tool/BaseAxeItem.java | 34 +++ .../java/ru/bclib/items/tool/BaseHoeItem.java | 19 ++ .../ru/bclib/items/tool/BasePickaxeItem.java | 42 ++++ .../ru/bclib/items/tool/BaseShovelItem.java | 42 ++++ .../ru/bclib/items/tool/BaseSwordItem.java | 20 ++ .../ru/bclib/registry/BaseBlockEntities.java | 90 ++++++++ .../registry/BaseBlockEntityRenders.java | 15 ++ .../java/ru/bclib/registry/BaseRegistry.java | 50 +++++ .../ru/bclib/registry/BlocksRegistry.java | 49 +++++ .../java/ru/bclib/registry/ItemsRegistry.java | 111 ++++++++++ 45 files changed, 1684 insertions(+), 40 deletions(-) create mode 100644 src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java create mode 100644 src/main/java/ru/bclib/blockentities/BaseChestBlockEntity.java create mode 100644 src/main/java/ru/bclib/blockentities/BaseFurnaceBlockEntity.java create mode 100644 src/main/java/ru/bclib/blockentities/BaseSignBlockEntity.java create mode 100644 src/main/java/ru/bclib/blocks/BaseBarrelBlock.java create mode 100644 src/main/java/ru/bclib/blocks/BaseChestBlock.java create mode 100644 src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java create mode 100644 src/main/java/ru/bclib/blocks/BaseSignBlock.java create mode 100644 src/main/java/ru/bclib/client/render/BaseChestBlockEntityRenderer.java create mode 100644 src/main/java/ru/bclib/client/render/BaseSignBlockEntityRenderer.java create mode 100644 src/main/java/ru/bclib/interfaces/IColorProvider.java rename src/main/java/ru/bclib/interfaces/{IRenderTypeable.java => IRenderTyped.java} (50%) create mode 100644 src/main/java/ru/bclib/interfaces/ISpetialItem.java create mode 100644 src/main/java/ru/bclib/items/BaseArmorItem.java create mode 100644 src/main/java/ru/bclib/items/BaseAttribute.java create mode 100644 src/main/java/ru/bclib/items/BaseBucketItem.java create mode 100644 src/main/java/ru/bclib/items/BaseDrinkItem.java create mode 100644 src/main/java/ru/bclib/items/BaseSpawnEggItem.java create mode 100644 src/main/java/ru/bclib/items/EndDiscItem.java create mode 100644 src/main/java/ru/bclib/items/ModelProviderItem.java create mode 100644 src/main/java/ru/bclib/items/tool/BaseAxeItem.java create mode 100644 src/main/java/ru/bclib/items/tool/BaseHoeItem.java create mode 100644 src/main/java/ru/bclib/items/tool/BasePickaxeItem.java create mode 100644 src/main/java/ru/bclib/items/tool/BaseShovelItem.java create mode 100644 src/main/java/ru/bclib/items/tool/BaseSwordItem.java create mode 100644 src/main/java/ru/bclib/registry/BaseBlockEntities.java create mode 100644 src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java create mode 100644 src/main/java/ru/bclib/registry/BaseRegistry.java create mode 100644 src/main/java/ru/bclib/registry/BlocksRegistry.java create mode 100644 src/main/java/ru/bclib/registry/ItemsRegistry.java diff --git a/src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java b/src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java new file mode 100644 index 00000000..285a5aac --- /dev/null +++ b/src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java @@ -0,0 +1,143 @@ +package ru.bclib.blockentities; + +import net.minecraft.core.NonNullList; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.BarrelBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import ru.bclib.blocks.BaseBarrelBlock; +import ru.bclib.registry.BaseBlockEntities; + +public class BaseBarrelBlockEntity extends RandomizableContainerBlockEntity { + private NonNullList inventory; + private int viewerCount; + + private BaseBarrelBlockEntity(BlockEntityType type) { + super(type); + this.inventory = NonNullList.withSize(27, ItemStack.EMPTY); + } + + public BaseBarrelBlockEntity() { + this(BaseBlockEntities.BARREL); + } + + public CompoundTag save(CompoundTag tag) { + super.save(tag); + if (!this.trySaveLootTable(tag)) { + ContainerHelper.saveAllItems(tag, this.inventory); + } + + return tag; + } + + public void load(BlockState state, CompoundTag tag) { + super.load(state, tag); + this.inventory = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); + if (!this.tryLoadLootTable(tag)) { + ContainerHelper.loadAllItems(tag, this.inventory); + } + } + + public int getContainerSize() { + return 27; + } + + protected NonNullList getItems() { + return this.inventory; + } + + protected void setItems(NonNullList list) { + this.inventory = list; + } + + protected Component getDefaultName() { + return new TranslatableComponent("container.barrel"); + } + + protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { + return ChestMenu.threeRows(syncId, playerInventory, this); + } + + public void startOpen(Player player) { + if (!player.isSpectator()) { + if (viewerCount < 0) { + viewerCount = 0; + } + + ++viewerCount; + BlockState blockState = this.getBlockState(); + if (!blockState.getValue(BarrelBlock.OPEN)) { + playSound(blockState, SoundEvents.BARREL_OPEN); + setOpen(blockState, true); + } + + if (level != null) { + scheduleUpdate(); + } + } + } + + @SuppressWarnings("ConstantConditions") + private void scheduleUpdate() { + level.getBlockTicks().scheduleTick(getBlockPos(), getBlockState().getBlock(), 5); + } + + public void tick() { + if (level != null) { + int x = worldPosition.getX(); + int y = worldPosition.getY(); + int z = worldPosition.getZ(); + viewerCount = ChestBlockEntity.getOpenCount(level, this, x, y, z); + if (viewerCount > 0) { + scheduleUpdate(); + } else { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof BaseBarrelBlock)) { + setRemoved(); + return; + } + if (blockState.getValue(BarrelBlock.OPEN)) { + playSound(blockState, SoundEvents.BARREL_CLOSE); + setOpen(blockState, false); + } + } + } + } + + public void stopOpen(Player player) { + if (!player.isSpectator()) { + --this.viewerCount; + } + } + + private void setOpen(BlockState state, boolean open) { + if (level != null) { + level.setBlock(this.getBlockPos(), state.setValue(BarrelBlock.OPEN, open), 3); + } + } + + private void playSound(BlockState blockState, SoundEvent soundEvent) { + if (level != null) { + Vec3i vec3i = blockState.getValue(BarrelBlock.FACING).getNormal(); + double d = (double) this.worldPosition.getX() + 0.5D + (double) vec3i.getX() / 2.0D; + double e = (double) this.worldPosition.getY() + 0.5D + (double) vec3i.getY() / 2.0D; + double f = (double) this.worldPosition.getZ() + 0.5D + (double) vec3i.getZ() / 2.0D; + level.playSound(null, d, e, f, soundEvent, SoundSource.BLOCKS, 0.5F, + this.level.random.nextFloat() * 0.1F + 0.9F); + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/bclib/blockentities/BaseChestBlockEntity.java b/src/main/java/ru/bclib/blockentities/BaseChestBlockEntity.java new file mode 100644 index 00000000..2d1ed5d4 --- /dev/null +++ b/src/main/java/ru/bclib/blockentities/BaseChestBlockEntity.java @@ -0,0 +1,10 @@ +package ru.bclib.blockentities; + +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import ru.bclib.registry.BaseBlockEntities; + +public class BaseChestBlockEntity extends ChestBlockEntity { + public BaseChestBlockEntity() { + super(BaseBlockEntities.CHEST); + } +} diff --git a/src/main/java/ru/bclib/blockentities/BaseFurnaceBlockEntity.java b/src/main/java/ru/bclib/blockentities/BaseFurnaceBlockEntity.java new file mode 100644 index 00000000..7413bd7c --- /dev/null +++ b/src/main/java/ru/bclib/blockentities/BaseFurnaceBlockEntity.java @@ -0,0 +1,24 @@ +package ru.bclib.blockentities; + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.FurnaceMenu; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; +import ru.bclib.registry.BaseBlockEntities; + +public class BaseFurnaceBlockEntity extends AbstractFurnaceBlockEntity { + public BaseFurnaceBlockEntity() { + super(BaseBlockEntities.FURNACE, RecipeType.SMELTING); + } + + protected Component getDefaultName() { + return new TranslatableComponent("container.furnace"); + } + + protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { + return new FurnaceMenu(syncId, playerInventory, this, this.dataAccess); + } +} diff --git a/src/main/java/ru/bclib/blockentities/BaseSignBlockEntity.java b/src/main/java/ru/bclib/blockentities/BaseSignBlockEntity.java new file mode 100644 index 00000000..90bf2a21 --- /dev/null +++ b/src/main/java/ru/bclib/blockentities/BaseSignBlockEntity.java @@ -0,0 +1,16 @@ +package ru.bclib.blockentities; + +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import ru.bclib.registry.BaseBlockEntities; + +public class BaseSignBlockEntity extends SignBlockEntity { + public BaseSignBlockEntity() { + super(); + } + + @Override + public BlockEntityType getType() { + return BaseBlockEntities.SIGN; + } +} \ No newline at end of file diff --git a/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java b/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java index 0e377e29..69b39171 100644 --- a/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java @@ -29,11 +29,9 @@ import ru.bclib.client.models.PatternsHelper; public class BaseAnvilBlock extends AnvilBlock implements BlockModelProvider { private static final IntegerProperty DESTRUCTION = BlockProperties.DESTRUCTION; - protected final int level; - public BaseAnvilBlock(MaterialColor color, int level) { + public BaseAnvilBlock(MaterialColor color) { super(FabricBlockSettings.copyOf(Blocks.ANVIL).materialColor(color)); - this.level = level; } @Override @@ -45,10 +43,6 @@ public class BaseAnvilBlock extends AnvilBlock implements BlockModelProvider { public IntegerProperty getDestructionProperty() { return DESTRUCTION; } - - public int getCraftingLevel() { - return level; - } @Override public List getDrops(BlockState state, LootContext.Builder builder) { diff --git a/src/main/java/ru/bclib/blocks/BaseBarrelBlock.java b/src/main/java/ru/bclib/blocks/BaseBarrelBlock.java new file mode 100644 index 00000000..2a2de39d --- /dev/null +++ b/src/main/java/ru/bclib/blocks/BaseBarrelBlock.java @@ -0,0 +1,133 @@ +package ru.bclib.blocks; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Random; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.stats.Stats; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.monster.piglin.PiglinAi; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BarrelBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.phys.BlockHitResult; +import ru.bclib.blockentities.BaseBarrelBlockEntity; +import ru.bclib.client.models.BasePatterns; +import ru.bclib.client.models.BlockModelProvider; +import ru.bclib.client.models.ModelsHelper; +import ru.bclib.client.models.PatternsHelper; +import ru.bclib.registry.BaseBlockEntities; + +public class BaseBarrelBlock extends BarrelBlock implements BlockModelProvider { + public BaseBarrelBlock(Block source) { + super(FabricBlockSettings.copyOf(source).noOcclusion()); + } + + @Override + public BlockEntity newBlockEntity(BlockGetter world) { + return BaseBlockEntities.BARREL.create(); + } + + @Override + public List getDrops(BlockState state, LootContext.Builder builder) { + List drop = super.getDrops(state, builder); + drop.add(new ItemStack(this.asItem())); + return drop; + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hit) { + if (world.isClientSide) { + return InteractionResult.SUCCESS; + } else { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BaseBarrelBlockEntity) { + player.openMenu((BaseBarrelBlockEntity) blockEntity); + player.awardStat(Stats.OPEN_BARREL); + PiglinAi.angerNearbyPiglins(player, true); + } + + return InteractionResult.CONSUME; + } + } + + @Override + public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BaseBarrelBlockEntity) { + ((BaseBarrelBlockEntity) blockEntity).tick(); + } + } + + @Override + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Override + public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, + ItemStack itemStack) { + if (itemStack.hasCustomHoverName()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BaseBarrelBlockEntity) { + ((BaseBarrelBlockEntity) blockEntity).setCustomName(itemStack.getHoverName()); + } + } + } + + @Override + public BlockModel getItemModel(ResourceLocation blockId) { + return getBlockModel(blockId, defaultBlockState()); + } + + @Override + public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) { + Optional pattern; + if (blockState.getValue(OPEN)) { + pattern = PatternsHelper.createJson(BasePatterns.BLOCK_BARREL_OPEN, blockId); + } else { + pattern = PatternsHelper.createJson(BasePatterns.BLOCK_BOTTOM_TOP, blockId); + } + return ModelsHelper.fromPattern(pattern); + } + + @Override + public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map modelCache) { + String open = blockState.getValue(OPEN) ? "_open" : ""; + ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), + "block/" + stateId.getPath() + open); + registerBlockModel(stateId, modelId, blockState, modelCache); + Direction facing = blockState.getValue(FACING); + BlockModelRotation rotation = BlockModelRotation.X0_Y0; + switch (facing) { + case NORTH: rotation = BlockModelRotation.X90_Y0; break; + case EAST: rotation = BlockModelRotation.X90_Y90; break; + case SOUTH: rotation = BlockModelRotation.X90_Y180; break; + case WEST: rotation = BlockModelRotation.X90_Y270; break; + case DOWN: + default: rotation = BlockModelRotation.X180_Y0; break; + } + return ModelsHelper.createMultiVariant(modelId, rotation.getRotation(), false); + } +} diff --git a/src/main/java/ru/bclib/blocks/BaseChainBlock.java b/src/main/java/ru/bclib/blocks/BaseChainBlock.java index 7d7693a3..e23827f8 100644 --- a/src/main/java/ru/bclib/blocks/BaseChainBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseChainBlock.java @@ -23,9 +23,9 @@ import ru.bclib.client.models.BlockModelProvider; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public class BaseChainBlock extends ChainBlock implements BlockModelProvider, IRenderTypeable { +public class BaseChainBlock extends ChainBlock implements BlockModelProvider, IRenderTyped { public BaseChainBlock(MaterialColor color) { super(FabricBlockSettings.copyOf(Blocks.CHAIN).materialColor(color)); } diff --git a/src/main/java/ru/bclib/blocks/BaseChestBlock.java b/src/main/java/ru/bclib/blocks/BaseChestBlock.java new file mode 100644 index 00000000..2f8f02b2 --- /dev/null +++ b/src/main/java/ru/bclib/blocks/BaseChestBlock.java @@ -0,0 +1,58 @@ +package ru.bclib.blocks; + +import java.util.List; +import java.util.Optional; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootContext; +import ru.bclib.client.models.BasePatterns; +import ru.bclib.client.models.BlockModelProvider; +import ru.bclib.client.models.ModelsHelper; +import ru.bclib.client.models.PatternsHelper; +import ru.bclib.registry.BaseBlockEntities; + +public class BaseChestBlock extends ChestBlock implements BlockModelProvider { + private final Block parent; + + public BaseChestBlock(Block source) { + super(FabricBlockSettings.copyOf(source).noOcclusion(), () -> BaseBlockEntities.CHEST); + this.parent = source; + } + + @Override + public BlockEntity newBlockEntity(BlockGetter world) + { + return BaseBlockEntities.CHEST.create(); + } + + @Override + public List getDrops(BlockState state, LootContext.Builder builder) + { + List drop = super.getDrops(state, builder); + drop.add(new ItemStack(this.asItem())); + return drop; + } + + @Override + public BlockModel getItemModel(ResourceLocation blockId) { + Optional pattern = PatternsHelper.createJson(BasePatterns.ITEM_CHEST, blockId); + return ModelsHelper.fromPattern(pattern); + } + + @Override + public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) { + ResourceLocation parentId = Registry.BLOCK.getKey(parent); + return ModelsHelper.createBlockEmpty(parentId); + } +} diff --git a/src/main/java/ru/bclib/blocks/BaseDoorBlock.java b/src/main/java/ru/bclib/blocks/BaseDoorBlock.java index 8ebc1311..628b87a6 100644 --- a/src/main/java/ru/bclib/blocks/BaseDoorBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseDoorBlock.java @@ -26,9 +26,9 @@ import ru.bclib.client.models.BlockModelProvider; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public class BaseDoorBlock extends DoorBlock implements IRenderTypeable, BlockModelProvider { +public class BaseDoorBlock extends DoorBlock implements IRenderTyped, BlockModelProvider { public BaseDoorBlock(Block source) { super(FabricBlockSettings.copyOf(source).strength(3F, 3F).noOcclusion()); } diff --git a/src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java b/src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java new file mode 100644 index 00000000..fd23688e --- /dev/null +++ b/src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java @@ -0,0 +1,105 @@ +package ru.bclib.blocks; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.stats.Stats; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.FurnaceBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import ru.bclib.blockentities.BaseFurnaceBlockEntity; +import ru.bclib.client.models.BasePatterns; +import ru.bclib.client.models.BlockModelProvider; +import ru.bclib.client.models.ModelsHelper; +import ru.bclib.client.models.PatternsHelper; +import ru.bclib.client.render.ERenderLayer; +import ru.bclib.interfaces.IRenderTyped; + +public class BaseFurnaceBlock extends FurnaceBlock implements BlockModelProvider, IRenderTyped { + public BaseFurnaceBlock(Block source) { + super(FabricBlockSettings.copyOf(source).luminance(state -> state.getValue(LIT) ? 13 : 0)); + } + + @Override + public BlockEntity newBlockEntity(BlockGetter world) { + return new BaseFurnaceBlockEntity(); + } + + @Override + protected void openContainer(Level world, BlockPos pos, Player player) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BaseFurnaceBlockEntity) { + player.openMenu((MenuProvider) blockEntity); + player.awardStat(Stats.INTERACT_WITH_FURNACE); + } + } + + @Override + public @Nullable BlockModel getBlockModel(ResourceLocation blockId, BlockState blockState) { + String blockName = blockId.getPath(); + Map textures = Maps.newHashMap(); + textures.put("%top%", blockName + "_top"); + textures.put("%side%", blockName + "_side"); + Optional pattern; + if (blockState.getValue(LIT)) { + textures.put("%front%", blockName + "_front_on"); + textures.put("%glow%", blockName + "_glow"); + pattern = PatternsHelper.createJson(BasePatterns.BLOCK_FURNACE_LIT, textures); + } else { + textures.put("%front%", blockName + "_front"); + pattern = PatternsHelper.createJson(BasePatterns.BLOCK_FURNACE, textures); + } + return ModelsHelper.fromPattern(pattern); + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return getBlockModel(resourceLocation, defaultBlockState()); + } + + @Override + public UnbakedModel getModelVariant(ResourceLocation stateId, BlockState blockState, Map modelCache) { + String lit = blockState.getValue(LIT) ? "_lit" : ""; + ResourceLocation modelId = new ResourceLocation(stateId.getNamespace(), + "block/" + stateId.getPath() + lit); + registerBlockModel(stateId, modelId, blockState, modelCache); + return ModelsHelper.createFacingModel(modelId, blockState.getValue(FACING), false, true); + } + + @Override + public ERenderLayer getRenderLayer() { + return ERenderLayer.CUTOUT; + } + + @Override + public List getDrops(BlockState state, LootContext.Builder builder) { + List drop = Lists.newArrayList(new ItemStack(this)); + BlockEntity blockEntity = builder.getOptionalParameter(LootContextParams.BLOCK_ENTITY); + if (blockEntity instanceof BaseFurnaceBlockEntity) { + BaseFurnaceBlockEntity entity = (BaseFurnaceBlockEntity) blockEntity; + for (int i = 0; i < entity.getContainerSize(); i++) { + drop.add(entity.getItem(i)); + } + } + return drop; + } +} diff --git a/src/main/java/ru/bclib/blocks/BaseLadderBlock.java b/src/main/java/ru/bclib/blocks/BaseLadderBlock.java index 4a60d045..d057f971 100644 --- a/src/main/java/ru/bclib/blocks/BaseLadderBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseLadderBlock.java @@ -34,10 +34,10 @@ import ru.bclib.client.models.BasePatterns; import ru.bclib.client.models.BlockModelProvider; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; import ru.bclib.util.BlocksHelper; -public class BaseLadderBlock extends BaseBlockNotFull implements IRenderTypeable, BlockModelProvider { +public class BaseLadderBlock extends BaseBlockNotFull implements IRenderTyped, BlockModelProvider { public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; protected static final VoxelShape EAST_SHAPE = Block.box(0.0D, 0.0D, 0.0D, 3.0D, 16.0D, 16.0D); diff --git a/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java b/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java index b407e30b..4d0652da 100644 --- a/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java @@ -21,10 +21,10 @@ import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import ru.bclib.client.models.BlockModelProvider; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; import ru.bclib.util.MHelper; -public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider, IRenderTypeable { +public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider, IRenderTyped { private final Block sapling; public BaseLeavesBlock(Block sapling, MaterialColor color) { diff --git a/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java b/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java index 084201c2..5a612ac0 100644 --- a/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java @@ -26,9 +26,9 @@ import ru.bclib.client.models.BlockModelProvider; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public class BaseMetalBarsBlock extends IronBarsBlock implements BlockModelProvider, IRenderTypeable { +public class BaseMetalBarsBlock extends IronBarsBlock implements BlockModelProvider, IRenderTyped { public BaseMetalBarsBlock(Block source) { super(FabricBlockSettings.copyOf(source).strength(5.0F, 6.0F).noOcclusion()); } diff --git a/src/main/java/ru/bclib/blocks/BasePlantBlock.java b/src/main/java/ru/bclib/blocks/BasePlantBlock.java index cbe50461..9180a4b0 100644 --- a/src/main/java/ru/bclib/blocks/BasePlantBlock.java +++ b/src/main/java/ru/bclib/blocks/BasePlantBlock.java @@ -30,11 +30,10 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -import ru.bclib.api.TagAPI; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public abstract class BasePlantBlock extends BaseBlockNotFull implements IRenderTypeable, BonemealableBlock { +public abstract class BasePlantBlock extends BaseBlockNotFull implements IRenderTyped, BonemealableBlock { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12); public BasePlantBlock() { diff --git a/src/main/java/ru/bclib/blocks/BaseSignBlock.java b/src/main/java/ru/bclib/blocks/BaseSignBlock.java new file mode 100644 index 00000000..f762f22d --- /dev/null +++ b/src/main/java/ru/bclib/blocks/BaseSignBlock.java @@ -0,0 +1,196 @@ +package ru.bclib.blocks; + +import java.util.Collections; +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Registry; +import net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.SignBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.block.state.properties.WoodType; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import ru.bclib.blockentities.BaseSignBlockEntity; +import ru.bclib.client.models.BlockModelProvider; +import ru.bclib.client.models.ModelsHelper; +import ru.bclib.interfaces.ISpetialItem; +import ru.bclib.util.BlocksHelper; + +public class BaseSignBlock extends SignBlock implements BlockModelProvider, ISpetialItem { + public static final IntegerProperty ROTATION = BlockStateProperties.ROTATION_16; + public static final BooleanProperty FLOOR = BooleanProperty.create("floor"); + private static final VoxelShape[] WALL_SHAPES = new VoxelShape[] { + Block.box(0.0D, 4.5D, 14.0D, 16.0D, 12.5D, 16.0D), + Block.box(0.0D, 4.5D, 0.0D, 2.0D, 12.5D, 16.0D), + Block.box(0.0D, 4.5D, 0.0D, 16.0D, 12.5D, 2.0D), + Block.box(14.0D, 4.5D, 0.0D, 16.0D, 12.5D, 16.0D) + }; + + private final Block parent; + + public BaseSignBlock(Block source) { + super(FabricBlockSettings.copyOf(source).strength(1.0F, 1.0F).noCollission().noOcclusion(), WoodType.OAK); + this.registerDefaultState(this.stateDefinition.any().setValue(ROTATION, 0).setValue(FLOOR, false).setValue(WATERLOGGED, false)); + this.parent = source; + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(ROTATION, FLOOR, WATERLOGGED); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) { + return state.getValue(FLOOR) ? SHAPE : WALL_SHAPES[state.getValue(ROTATION) >> 2]; + } + + @Override + public BlockEntity newBlockEntity(BlockGetter world) { + return new BaseSignBlockEntity(); + } + + @Override + public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) { + if (placer instanceof Player) { + BaseSignBlockEntity sign = (BaseSignBlockEntity) world.getBlockEntity(pos); + if (sign != null) { + if (!world.isClientSide) { + sign.setAllowedPlayerEditor((Player) placer); + ((ServerPlayer) placer).connection.send(new ClientboundOpenSignEditorPacket(pos)); + } else { + sign.setEditable(true); + } + } + } + } + + @Override + public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { + if (state.getValue(WATERLOGGED)) { + world.getLiquidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); + } + if (!canSurvive(state, world, pos)) { + return state.getValue(WATERLOGGED) ? state.getFluidState().createLegacyBlock() : Blocks.AIR.defaultBlockState(); + } + return super.updateShape(state, facing, neighborState, world, pos, neighborPos); + } + + @Override + public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { + if (!state.getValue(FLOOR)) { + int index = (((state.getValue(ROTATION) >> 2) + 2)) & 3; + return world.getBlockState(pos.relative(BlocksHelper.HORIZONTAL[index])).getMaterial().isSolid(); + } + else { + return world.getBlockState(pos.below()).getMaterial().isSolid(); + } + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { + if (ctx.getClickedFace() == Direction.UP) { + FluidState fluidState = ctx.getLevel().getFluidState(ctx.getClickedPos()); + return this.defaultBlockState().setValue(FLOOR, true) + .setValue(ROTATION, Mth.floor((180.0 + ctx.getRotation() * 16.0 / 360.0) + 0.5 - 12) & 15) + .setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER); + } else if (ctx.getClickedFace() != Direction.DOWN) { + BlockState blockState = this.defaultBlockState(); + FluidState fluidState = ctx.getLevel().getFluidState(ctx.getClickedPos()); + LevelReader worldView = ctx.getLevel(); + BlockPos blockPos = ctx.getClickedPos(); + Direction[] directions = ctx.getNearestLookingDirections(); + + for (Direction direction : directions) { + if (direction.getAxis().isHorizontal()) { + Direction dir = direction.getOpposite(); + int rot = Mth.floor((180.0 + dir.toYRot() * 16.0 / 360.0) + 0.5 + 4) & 15; + blockState = blockState.setValue(ROTATION, rot); + if (blockState.canSurvive(worldView, blockPos)) { + return blockState.setValue(FLOOR, false).setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER); + } + } + } + } + + return null; + } + + @Override + public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) { + ResourceLocation parentId = Registry.BLOCK.getKey(parent); + return ModelsHelper.createBlockEmpty(parentId); + } + + @Override + public BlockState rotate(BlockState state, Rotation rotation) { + return state.setValue(ROTATION, rotation.rotate((Integer) state.getValue(ROTATION), 16)); + } + + @Override + public BlockState mirror(BlockState state, Mirror mirror) { + return state.setValue(ROTATION, mirror.mirror((Integer) state.getValue(ROTATION), 16)); + } + + @Override + public List getDrops(BlockState state, LootContext.Builder builder) { + return Collections.singletonList(new ItemStack(this)); + } + + @Override + public Fluid takeLiquid(LevelAccessor world, BlockPos pos, BlockState state) { + // TODO Auto-generated method stub + return super.takeLiquid(world, pos, state); + } + + @Override + public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) { + // TODO Auto-generated method stub + return super.canPlaceLiquid(world, pos, state, fluid); + } + + @Override + public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) { + // TODO Auto-generated method stub + return super.placeLiquid(world, pos, state, fluidState); + } + + @Override + public int getStackSize() { + return 16; + } + + @Override + public boolean canPlaceOnWater() { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java b/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java index 16b433f7..f685df52 100644 --- a/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java @@ -24,9 +24,9 @@ import ru.bclib.client.models.BlockModelProvider; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public class BaseTrapdoorBlock extends TrapDoorBlock implements IRenderTypeable, BlockModelProvider { +public class BaseTrapdoorBlock extends TrapDoorBlock implements IRenderTyped, BlockModelProvider { public BaseTrapdoorBlock(Block source) { super(FabricBlockSettings.copyOf(source).strength(3.0F, 3.0F).noOcclusion()); } diff --git a/src/main/java/ru/bclib/blocks/DoublePlantBlock.java b/src/main/java/ru/bclib/blocks/DoublePlantBlock.java index 4a616d23..45c27019 100644 --- a/src/main/java/ru/bclib/blocks/DoublePlantBlock.java +++ b/src/main/java/ru/bclib/blocks/DoublePlantBlock.java @@ -35,10 +35,10 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; import ru.bclib.util.BlocksHelper; -public abstract class DoublePlantBlock extends BaseBlockNotFull implements IRenderTypeable, BonemealableBlock { +public abstract class DoublePlantBlock extends BaseBlockNotFull implements IRenderTyped, BonemealableBlock { private static final VoxelShape SHAPE = Block.box(4, 2, 4, 12, 16, 12); public static final IntegerProperty ROTATION = BlockProperties.ROTATION; public static final BooleanProperty TOP = BooleanProperty.create("top"); diff --git a/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java b/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java index 6341cd64..387c3d24 100644 --- a/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java +++ b/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java @@ -17,7 +17,6 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SaplingBlock; @@ -33,9 +32,9 @@ import ru.bclib.client.models.BlockModelProvider; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public abstract class FeatureSaplingBlock extends SaplingBlock implements IRenderTypeable, BlockModelProvider { +public abstract class FeatureSaplingBlock extends SaplingBlock implements IRenderTyped, BlockModelProvider { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12); public FeatureSaplingBlock() { diff --git a/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java b/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java index b95c5f1e..4de8acf2 100644 --- a/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java +++ b/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java @@ -5,9 +5,9 @@ import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.material.Material; import net.minecraft.world.level.material.MaterialColor; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public class SimpleLeavesBlock extends BaseBlockNotFull implements IRenderTypeable { +public class SimpleLeavesBlock extends BaseBlockNotFull implements IRenderTyped { public SimpleLeavesBlock(MaterialColor color) { super(FabricBlockSettings.of(Material.LEAVES) .strength(0.2F) diff --git a/src/main/java/ru/bclib/blocks/StalactiteBlock.java b/src/main/java/ru/bclib/blocks/StalactiteBlock.java index 63dfbf71..a77c3832 100644 --- a/src/main/java/ru/bclib/blocks/StalactiteBlock.java +++ b/src/main/java/ru/bclib/blocks/StalactiteBlock.java @@ -39,9 +39,9 @@ import ru.bclib.client.models.BasePatterns; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public class StalactiteBlock extends BaseBlockNotFull implements SimpleWaterloggedBlock, LiquidBlockContainer, IRenderTypeable { +public class StalactiteBlock extends BaseBlockNotFull implements SimpleWaterloggedBlock, LiquidBlockContainer, IRenderTyped { public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; public static final BooleanProperty IS_FLOOR = BlockProperties.IS_FLOOR; public static final IntegerProperty SIZE = BlockProperties.SIZE; diff --git a/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java b/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java index df7c5528..113c481e 100644 --- a/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java +++ b/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java @@ -35,9 +35,9 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements IRenderTypeable, BonemealableBlock, LiquidBlockContainer { +public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements IRenderTyped, BonemealableBlock, LiquidBlockContainer { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12); public UnderwaterPlantBlock() { diff --git a/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java b/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java index ce4c0fe5..95a7d2f7 100644 --- a/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java +++ b/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java @@ -27,9 +27,9 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; -public abstract class UpDownPlantBlock extends BaseBlockNotFull implements IRenderTypeable { +public abstract class UpDownPlantBlock extends BaseBlockNotFull implements IRenderTyped { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 16, 12); public UpDownPlantBlock() { diff --git a/src/main/java/ru/bclib/blocks/VineBlock.java b/src/main/java/ru/bclib/blocks/VineBlock.java index e091196b..e621109d 100644 --- a/src/main/java/ru/bclib/blocks/VineBlock.java +++ b/src/main/java/ru/bclib/blocks/VineBlock.java @@ -34,10 +34,10 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import ru.bclib.blocks.BlockProperties.TripleShape; import ru.bclib.client.render.ERenderLayer; -import ru.bclib.interfaces.IRenderTypeable; +import ru.bclib.interfaces.IRenderTyped; import ru.bclib.util.BlocksHelper; -public class VineBlock extends BaseBlockNotFull implements IRenderTypeable, BonemealableBlock { +public class VineBlock extends BaseBlockNotFull implements IRenderTyped, BonemealableBlock { public static final EnumProperty SHAPE = BlockProperties.TRIPLE_SHAPE; private static final VoxelShape VOXEL_SHAPE = Block.box(2, 0, 2, 14, 16, 14); diff --git a/src/main/java/ru/bclib/client/render/BaseChestBlockEntityRenderer.java b/src/main/java/ru/bclib/client/render/BaseChestBlockEntityRenderer.java new file mode 100644 index 00000000..7a93c0c8 --- /dev/null +++ b/src/main/java/ru/bclib/client/render/BaseChestBlockEntityRenderer.java @@ -0,0 +1,180 @@ +package ru.bclib.client.render; + +import java.util.HashMap; + +import com.google.common.collect.Maps; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; + +import it.unimi.dsi.fastutil.floats.Float2FloatFunction; +import it.unimi.dsi.fastutil.ints.Int2IntFunction; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BrightnessCombiner; +import net.minecraft.core.Direction; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.AbstractChestBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.DoubleBlockCombiner; +import net.minecraft.world.level.block.DoubleBlockCombiner.NeighborCombineResult; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.LidBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.ChestType; +import ru.bclib.blockentities.BaseChestBlockEntity; +import ru.bclib.blocks.BaseChestBlock; +import ru.bclib.registry.BaseRegistry; + +public class BaseChestBlockEntityRenderer extends BlockEntityRenderer { + private static final HashMap LAYERS = Maps.newHashMap(); + private static final RenderType[] defaultLayer; + + private static final int ID_NORMAL = 0; + private static final int ID_LEFT = 1; + private static final int ID_RIGHT = 2; + + private final ModelPart partA; + private final ModelPart partC; + private final ModelPart partB; + private final ModelPart partRightA; + private final ModelPart partRightC; + private final ModelPart partRightB; + private final ModelPart partLeftA; + private final ModelPart partLeftC; + private final ModelPart partLeftB; + + public BaseChestBlockEntityRenderer(BlockEntityRenderDispatcher blockEntityRenderDispatcher) { + super(blockEntityRenderDispatcher); + + this.partC = new ModelPart(64, 64, 0, 19); + this.partC.addBox(1.0F, 0.0F, 1.0F, 14.0F, 9.0F, 14.0F, 0.0F); + this.partA = new ModelPart(64, 64, 0, 0); + this.partA.addBox(1.0F, 0.0F, 0.0F, 14.0F, 5.0F, 14.0F, 0.0F); + this.partA.y = 9.0F; + this.partA.z = 1.0F; + this.partB = new ModelPart(64, 64, 0, 0); + this.partB.addBox(7.0F, -1.0F, 15.0F, 2.0F, 4.0F, 1.0F, 0.0F); + this.partB.y = 8.0F; + this.partRightC = new ModelPart(64, 64, 0, 19); + this.partRightC.addBox(1.0F, 0.0F, 1.0F, 15.0F, 9.0F, 14.0F, 0.0F); + this.partRightA = new ModelPart(64, 64, 0, 0); + this.partRightA.addBox(1.0F, 0.0F, 0.0F, 15.0F, 5.0F, 14.0F, 0.0F); + this.partRightA.y = 9.0F; + this.partRightA.z = 1.0F; + this.partRightB = new ModelPart(64, 64, 0, 0); + this.partRightB.addBox(15.0F, -1.0F, 15.0F, 1.0F, 4.0F, 1.0F, 0.0F); + this.partRightB.y = 8.0F; + this.partLeftC = new ModelPart(64, 64, 0, 19); + this.partLeftC.addBox(0.0F, 0.0F, 1.0F, 15.0F, 9.0F, 14.0F, 0.0F); + this.partLeftA = new ModelPart(64, 64, 0, 0); + this.partLeftA.addBox(0.0F, 0.0F, 0.0F, 15.0F, 5.0F, 14.0F, 0.0F); + this.partLeftA.y = 9.0F; + this.partLeftA.z = 1.0F; + this.partLeftB = new ModelPart(64, 64, 0, 0); + this.partLeftB.addBox(0.0F, -1.0F, 15.0F, 1.0F, 4.0F, 1.0F, 0.0F); + this.partLeftB.y = 8.0F; + } + + public void render(BaseChestBlockEntity entity, float tickDelta, PoseStack matrices, MultiBufferSource vertexConsumers, int light, int overlay) { + Level world = entity.getLevel(); + boolean worldExists = world != null; + BlockState blockState = worldExists ? entity.getBlockState() : (BlockState) Blocks.CHEST.defaultBlockState().setValue(ChestBlock.FACING, Direction.SOUTH); + ChestType chestType = blockState.hasProperty(ChestBlock.TYPE) ? (ChestType) blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE; + Block block = blockState.getBlock(); + if (block instanceof AbstractChestBlock) { + AbstractChestBlock abstractChestBlock = (AbstractChestBlock) block; + boolean isDouble = chestType != ChestType.SINGLE; + float f = ((Direction) blockState.getValue(ChestBlock.FACING)).toYRot(); + NeighborCombineResult propertySource; + + matrices.pushPose(); + matrices.translate(0.5D, 0.5D, 0.5D); + matrices.mulPose(Vector3f.YP.rotationDegrees(-f)); + matrices.translate(-0.5D, -0.5D, -0.5D); + + if (worldExists) { + propertySource = abstractChestBlock.combine(blockState, world, entity.getBlockPos(), true); + } else { + propertySource = DoubleBlockCombiner.Combiner::acceptNone; + } + + float pitch = ((Float2FloatFunction) propertySource.apply(ChestBlock.opennessCombiner((LidBlockEntity) entity))).get(tickDelta); + pitch = 1.0F - pitch; + pitch = 1.0F - pitch * pitch * pitch; + @SuppressWarnings({ "unchecked", "rawtypes" }) + int blockLight = ((Int2IntFunction) propertySource.apply(new BrightnessCombiner())).applyAsInt(light); + + VertexConsumer vertexConsumer = getConsumer(vertexConsumers, block, chestType); + + if (isDouble) { + if (chestType == ChestType.LEFT) { + renderParts(matrices, vertexConsumer, this.partLeftA, this.partLeftB, this.partLeftC, pitch, blockLight, overlay); + } else { + renderParts(matrices, vertexConsumer, this.partRightA, this.partRightB, this.partRightC, pitch, blockLight, overlay); + } + } else { + renderParts(matrices, vertexConsumer, this.partA, this.partB, this.partC, pitch, blockLight, overlay); + } + + matrices.popPose(); + } + } + + private void renderParts(PoseStack matrices, VertexConsumer vertices, ModelPart modelPart, ModelPart modelPart2, ModelPart modelPart3, float pitch, int light, int overlay) { + modelPart.xRot = -(pitch * 1.5707964F); + modelPart2.xRot = modelPart.xRot; + modelPart.render(matrices, vertices, light, overlay); + modelPart2.render(matrices, vertices, light, overlay); + modelPart3.render(matrices, vertices, light, overlay); + } + + private static RenderType getChestTexture(ChestType type, RenderType[] layers) { + switch (type) { + case LEFT: + return layers[ID_LEFT]; + case RIGHT: + return layers[ID_RIGHT]; + case SINGLE: + default: + return layers[ID_NORMAL]; + } + } + + public static VertexConsumer getConsumer(MultiBufferSource provider, Block block, ChestType chestType) { + RenderType[] layers = LAYERS.getOrDefault(block, defaultLayer); + return provider.getBuffer(getChestTexture(chestType, layers)); + } + + static { + defaultLayer = new RenderType[] { + RenderType.entityCutout(new ResourceLocation("textures/entity/chest/normal.png")), + RenderType.entityCutout(new ResourceLocation("textures/entity/chest/normal_left.png")), + RenderType.entityCutout(new ResourceLocation("textures/entity/chest/normal_right.png")) + }; + + BaseRegistry.getModBlocks().forEach((item) -> { + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof BaseChestBlock) { + ResourceLocation blockId = Registry.BLOCK.getKey(block); + String modId = blockId.getNamespace(); + String path = blockId.getPath(); + LAYERS.put(block, new RenderType[] { + RenderType.entityCutout(new ResourceLocation(modId, "textures/entity/chest/" + path + ".png")), + RenderType.entityCutout(new ResourceLocation(modId, "textures/entity/chest/" + path + "_left.png")), + RenderType.entityCutout(new ResourceLocation(modId, "textures/entity/chest/" + path + "_right.png")) + }); + } + } + }); + } +} diff --git a/src/main/java/ru/bclib/client/render/BaseSignBlockEntityRenderer.java b/src/main/java/ru/bclib/client/render/BaseSignBlockEntityRenderer.java new file mode 100644 index 00000000..069f71e8 --- /dev/null +++ b/src/main/java/ru/bclib/client/render/BaseSignBlockEntityRenderer.java @@ -0,0 +1,122 @@ +package ru.bclib.client.render; + +import java.util.HashMap; +import java.util.List; + +import com.google.common.collect.Maps; +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; + +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.SignRenderer; +import net.minecraft.client.renderer.blockentity.SignRenderer.SignModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SignBlock; +import net.minecraft.world.level.block.StandingSignBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.WoodType; +import ru.bclib.blockentities.BaseSignBlockEntity; +import ru.bclib.blocks.BaseSignBlock; +import ru.bclib.registry.BaseRegistry; + +public class BaseSignBlockEntityRenderer extends BlockEntityRenderer { + private static final HashMap LAYERS = Maps.newHashMap(); + private static final RenderType defaultLayer; + private final SignModel model = new SignRenderer.SignModel(); + + public BaseSignBlockEntityRenderer(BlockEntityRenderDispatcher dispatcher) { + super(dispatcher); + } + + public void render(BaseSignBlockEntity signBlockEntity, float tickDelta, PoseStack matrixStack, + MultiBufferSource provider, int light, int overlay) { + BlockState state = signBlockEntity.getBlockState(); + matrixStack.pushPose(); + + matrixStack.translate(0.5D, 0.5D, 0.5D); + float angle = -((float) ((Integer) state.getValue(StandingSignBlock.ROTATION) * 360) / 16.0F); + + BlockState blockState = signBlockEntity.getBlockState(); + if (blockState.getValue(BaseSignBlock.FLOOR)) { + matrixStack.mulPose(Vector3f.YP.rotationDegrees(angle)); + this.model.stick.visible = true; + } else { + matrixStack.mulPose(Vector3f.YP.rotationDegrees(angle + 180)); + matrixStack.translate(0.0D, -0.3125D, -0.4375D); + this.model.stick.visible = false; + } + + matrixStack.pushPose(); + matrixStack.scale(0.6666667F, -0.6666667F, -0.6666667F); + VertexConsumer vertexConsumer = getConsumer(provider, state.getBlock()); + model.sign.render(matrixStack, vertexConsumer, light, overlay); + model.stick.render(matrixStack, vertexConsumer, light, overlay); + matrixStack.popPose(); + Font textRenderer = renderer.getFont(); + matrixStack.translate(0.0D, 0.3333333432674408D, 0.046666666865348816D); + matrixStack.scale(0.010416667F, -0.010416667F, 0.010416667F); + int m = signBlockEntity.getColor().getTextColor(); + int n = (int) (NativeImage.getR(m) * 0.4D); + int o = (int) (NativeImage.getG(m) * 0.4D); + int p = (int) (NativeImage.getB(m) * 0.4D); + int q = NativeImage.combine(0, p, o, n); + + for (int s = 0; s < 4; ++s) { + FormattedCharSequence orderedText = signBlockEntity.getRenderMessage(s, (text) -> { + List list = textRenderer.split(text, 90); + return list.isEmpty() ? FormattedCharSequence.EMPTY : (FormattedCharSequence) list.get(0); + }); + if (orderedText != null) { + float t = (float) (-textRenderer.width(orderedText) / 2); + textRenderer.drawInBatch((FormattedCharSequence) orderedText, t, (float) (s * 10 - 20), q, false, matrixStack.last().pose(), provider, false, 0, light); + } + } + + matrixStack.popPose(); + } + + public static Material getModelTexture(Block block) { + WoodType signType2; + if (block instanceof SignBlock) { + signType2 = ((SignBlock) block).type(); + } else { + signType2 = WoodType.OAK; + } + + return Sheets.signTexture(signType2); + } + + public static VertexConsumer getConsumer(MultiBufferSource provider, Block block) { + return provider.getBuffer(LAYERS.getOrDefault(block, defaultLayer)); + } + + static { + defaultLayer = RenderType.entitySolid(new ResourceLocation("textures/entity/sign/oak.png")); + + BaseRegistry.getModBlocks().forEach((item) -> { + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof BaseSignBlock) { + ResourceLocation blockId = Registry.BLOCK.getKey(block); + RenderType layer = RenderType.entitySolid(new ResourceLocation(blockId.getNamespace(), + "textures/entity/sign/" + blockId.getPath() + ".png")); + LAYERS.put(block, layer); + } + } + }); + } + + +} diff --git a/src/main/java/ru/bclib/interfaces/IColorProvider.java b/src/main/java/ru/bclib/interfaces/IColorProvider.java new file mode 100644 index 00000000..c9f2f8b6 --- /dev/null +++ b/src/main/java/ru/bclib/interfaces/IColorProvider.java @@ -0,0 +1,10 @@ +package ru.bclib.interfaces; + +import net.minecraft.client.color.block.BlockColor; +import net.minecraft.client.color.item.ItemColor; + +public interface IColorProvider { + BlockColor getProvider(); + + ItemColor getItemProvider(); +} diff --git a/src/main/java/ru/bclib/interfaces/IRenderTypeable.java b/src/main/java/ru/bclib/interfaces/IRenderTyped.java similarity index 50% rename from src/main/java/ru/bclib/interfaces/IRenderTypeable.java rename to src/main/java/ru/bclib/interfaces/IRenderTyped.java index 145478d3..c82a009b 100644 --- a/src/main/java/ru/bclib/interfaces/IRenderTypeable.java +++ b/src/main/java/ru/bclib/interfaces/IRenderTyped.java @@ -2,7 +2,6 @@ package ru.bclib.interfaces; import ru.bclib.client.render.ERenderLayer; -public interface IRenderTypeable -{ - public ERenderLayer getRenderLayer(); +public interface IRenderTyped { + ERenderLayer getRenderLayer(); } diff --git a/src/main/java/ru/bclib/interfaces/ISpetialItem.java b/src/main/java/ru/bclib/interfaces/ISpetialItem.java new file mode 100644 index 00000000..33112bf7 --- /dev/null +++ b/src/main/java/ru/bclib/interfaces/ISpetialItem.java @@ -0,0 +1,6 @@ +package ru.bclib.interfaces; + +public interface ISpetialItem { + boolean canPlaceOnWater(); + int getStackSize(); +} diff --git a/src/main/java/ru/bclib/items/BaseArmorItem.java b/src/main/java/ru/bclib/items/BaseArmorItem.java new file mode 100644 index 00000000..805c2128 --- /dev/null +++ b/src/main/java/ru/bclib/items/BaseArmorItem.java @@ -0,0 +1,49 @@ +package ru.bclib.items; + +import java.util.UUID; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterial; +import ru.bclib.client.models.ItemModelProvider; + +public class BaseArmorItem extends ArmorItem implements ItemModelProvider { + + protected static final UUID[] ARMOR_MODIFIER_UUID_PER_SLOT = new UUID[] { + UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), + UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), + UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), + UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150") + }; + + protected final Multimap defaultModifiers; + + public BaseArmorItem(ArmorMaterial material, EquipmentSlot equipmentSlot, Properties settings) { + super(material, equipmentSlot, settings); + this.defaultModifiers = HashMultimap.create(); + UUID uuid = ARMOR_MODIFIER_UUID_PER_SLOT[equipmentSlot.getIndex()]; + addAttributeModifier(Attributes.ARMOR, new AttributeModifier(uuid, "Armor modifier", getDefense(), AttributeModifier.Operation.ADDITION)); + addAttributeModifier(Attributes.ARMOR_TOUGHNESS, new AttributeModifier(uuid, "Armor toughness", getToughness(), AttributeModifier.Operation.ADDITION)); + if (knockbackResistance > 0.0F) { + addAttributeModifier(Attributes.KNOCKBACK_RESISTANCE, new AttributeModifier(uuid, "Armor knockback resistance", knockbackResistance, AttributeModifier.Operation.ADDITION)); + } + } + + @Override + public Multimap getDefaultAttributeModifiers(EquipmentSlot equipmentSlot) { + return equipmentSlot == slot ? defaultModifiers : super.getDefaultAttributeModifiers(equipmentSlot); + } + + protected void addAttributeModifier(Attribute attribute, AttributeModifier modifier) { + if (defaultModifiers.containsKey(attribute)) { + defaultModifiers.removeAll(attribute); + } + defaultModifiers.put(attribute, modifier); + } +} diff --git a/src/main/java/ru/bclib/items/BaseAttribute.java b/src/main/java/ru/bclib/items/BaseAttribute.java new file mode 100644 index 00000000..69060830 --- /dev/null +++ b/src/main/java/ru/bclib/items/BaseAttribute.java @@ -0,0 +1,9 @@ +package ru.bclib.items; + +import net.minecraft.world.entity.ai.attributes.Attribute; + +public class BaseAttribute extends Attribute { + public BaseAttribute(String description, double value) { + super(description, value); + } +} diff --git a/src/main/java/ru/bclib/items/BaseBucketItem.java b/src/main/java/ru/bclib/items/BaseBucketItem.java new file mode 100644 index 00000000..e33ac83a --- /dev/null +++ b/src/main/java/ru/bclib/items/BaseBucketItem.java @@ -0,0 +1,13 @@ +package ru.bclib.items; + +import net.fabricmc.fabric.api.item.v1.FabricItemSettings; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.FishBucketItem; +import net.minecraft.world.level.material.Fluids; +import ru.bclib.client.models.ItemModelProvider; + +public class BaseBucketItem extends FishBucketItem implements ItemModelProvider { + public BaseBucketItem(EntityType type, FabricItemSettings settings) { + super(type, Fluids.WATER, settings.stacksTo(1)); + } +} diff --git a/src/main/java/ru/bclib/items/BaseDrinkItem.java b/src/main/java/ru/bclib/items/BaseDrinkItem.java new file mode 100644 index 00000000..66122ec0 --- /dev/null +++ b/src/main/java/ru/bclib/items/BaseDrinkItem.java @@ -0,0 +1,54 @@ +package ru.bclib.items; + +import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stats; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemUtils; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.UseAnim; +import net.minecraft.world.level.Level; + +public class BaseDrinkItem extends ModelProviderItem { + public BaseDrinkItem(Properties settings) { + super(settings); + } + + @Override + public int getUseDuration(ItemStack stack) { + return 32; + } + + @Override + public UseAnim getUseAnimation(ItemStack stack) { + return UseAnim.DRINK; + } + + @Override + public InteractionResultHolder use(Level world, Player user, InteractionHand hand) { + return ItemUtils.useDrink(world, user, hand); + } + + @Override + public ItemStack finishUsingItem(ItemStack stack, Level world, LivingEntity user) { + if (user instanceof ServerPlayer) { + ServerPlayer serverPlayerEntity = (ServerPlayer) user; + CriteriaTriggers.CONSUME_ITEM.trigger(serverPlayerEntity, stack); + serverPlayerEntity.awardStat(Stats.ITEM_USED.get(this)); + } + + if (user instanceof Player && !((Player) user).abilities.instabuild) { + stack.shrink(1); + } + + if (!world.isClientSide) { + user.removeAllEffects(); + } + + return stack.isEmpty() ? new ItemStack(Items.GLASS_BOTTLE) : stack; + } +} diff --git a/src/main/java/ru/bclib/items/BaseSpawnEggItem.java b/src/main/java/ru/bclib/items/BaseSpawnEggItem.java new file mode 100644 index 00000000..fb519f7e --- /dev/null +++ b/src/main/java/ru/bclib/items/BaseSpawnEggItem.java @@ -0,0 +1,24 @@ +package ru.bclib.items; + +import java.util.Optional; + +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.SpawnEggItem; +import ru.bclib.client.models.BasePatterns; +import ru.bclib.client.models.ItemModelProvider; +import ru.bclib.client.models.ModelsHelper; +import ru.bclib.client.models.PatternsHelper; + +public class BaseSpawnEggItem extends SpawnEggItem implements ItemModelProvider { + public BaseSpawnEggItem(EntityType type, int primaryColor, int secondaryColor, Properties settings) { + super(type, primaryColor, secondaryColor, settings); + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + Optional pattern = PatternsHelper.createJson(BasePatterns.ITEM_SPAWN_EGG, resourceLocation); + return ModelsHelper.fromPattern(pattern); + } +} diff --git a/src/main/java/ru/bclib/items/EndDiscItem.java b/src/main/java/ru/bclib/items/EndDiscItem.java new file mode 100644 index 00000000..dcae4586 --- /dev/null +++ b/src/main/java/ru/bclib/items/EndDiscItem.java @@ -0,0 +1,11 @@ +package ru.bclib.items; + +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.item.RecordItem; +import ru.bclib.client.models.ItemModelProvider; + +public class EndDiscItem extends RecordItem implements ItemModelProvider { + public EndDiscItem(int comparatorOutput, SoundEvent sound, Properties settings) { + super(comparatorOutput, sound, settings); + } +} diff --git a/src/main/java/ru/bclib/items/ModelProviderItem.java b/src/main/java/ru/bclib/items/ModelProviderItem.java new file mode 100644 index 00000000..208b8eb7 --- /dev/null +++ b/src/main/java/ru/bclib/items/ModelProviderItem.java @@ -0,0 +1,18 @@ +package ru.bclib.items; + +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import ru.bclib.client.models.ItemModelProvider; +import ru.bclib.client.models.ModelsHelper; + +public class ModelProviderItem extends Item implements ItemModelProvider { + public ModelProviderItem(Properties settings) { + super(settings); + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return ModelsHelper.createItemModel(resourceLocation); + } +} diff --git a/src/main/java/ru/bclib/items/tool/BaseAxeItem.java b/src/main/java/ru/bclib/items/tool/BaseAxeItem.java new file mode 100644 index 00000000..e3f5cf55 --- /dev/null +++ b/src/main/java/ru/bclib/items/tool/BaseAxeItem.java @@ -0,0 +1,34 @@ +package ru.bclib.items.tool; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; +import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.AxeItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Tier; +import net.minecraft.world.level.block.state.BlockState; +import ru.bclib.client.models.ItemModelProvider; +import ru.bclib.client.models.ModelsHelper; + +public class BaseAxeItem extends AxeItem implements DynamicAttributeTool, ItemModelProvider { + public BaseAxeItem(Tier material, float attackDamage, float attackSpeed, Properties settings) { + super(material, attackDamage, attackSpeed, settings); + } + + @Override + public int getMiningLevel(Tag tag, BlockState state, ItemStack stack, LivingEntity user) { + if (tag.equals(FabricToolTags.AXES)) { + return this.getTier().getLevel(); + } + return 0; + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return ModelsHelper.createHandheldItem(resourceLocation); + } +} diff --git a/src/main/java/ru/bclib/items/tool/BaseHoeItem.java b/src/main/java/ru/bclib/items/tool/BaseHoeItem.java new file mode 100644 index 00000000..f44a1af8 --- /dev/null +++ b/src/main/java/ru/bclib/items/tool/BaseHoeItem.java @@ -0,0 +1,19 @@ +package ru.bclib.items.tool; + +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.HoeItem; +import net.minecraft.world.item.Tier; +import ru.bclib.client.models.ItemModelProvider; +import ru.bclib.client.models.ModelsHelper; + +public class BaseHoeItem extends HoeItem implements ItemModelProvider { + public BaseHoeItem(Tier material, int attackDamage, float attackSpeed, Properties settings) { + super(material, attackDamage, attackSpeed, settings); + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return ModelsHelper.createHandheldItem(resourceLocation); + } +} diff --git a/src/main/java/ru/bclib/items/tool/BasePickaxeItem.java b/src/main/java/ru/bclib/items/tool/BasePickaxeItem.java new file mode 100644 index 00000000..858bb692 --- /dev/null +++ b/src/main/java/ru/bclib/items/tool/BasePickaxeItem.java @@ -0,0 +1,42 @@ +package ru.bclib.items.tool; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; +import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; +import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl; +import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl.Entry; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.PickaxeItem; +import net.minecraft.world.item.Tier; +import net.minecraft.world.level.block.state.BlockState; +import ru.bclib.client.models.ItemModelProvider; +import ru.bclib.client.models.ModelsHelper; + +public class BasePickaxeItem extends PickaxeItem implements DynamicAttributeTool, ItemModelProvider { + public BasePickaxeItem(Tier material, int attackDamage, float attackSpeed, Properties settings) { + super(material, attackDamage, attackSpeed, settings); + } + + @Override + public int getMiningLevel(Tag tag, BlockState state, ItemStack stack, LivingEntity user) { + if (tag.equals(FabricToolTags.PICKAXES)) { + return getTier().getLevel(); + } + return 0; + } + + @Override + public float getDestroySpeed(ItemStack stack, BlockState state) { + Entry entry = ToolManagerImpl.entryNullable(state.getBlock()); + return (entry != null && entry.getMiningLevel(FabricToolTags.PICKAXES) >= 0) ? speed : super.getDestroySpeed(stack, state); + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return ModelsHelper.createHandheldItem(resourceLocation); + } +} diff --git a/src/main/java/ru/bclib/items/tool/BaseShovelItem.java b/src/main/java/ru/bclib/items/tool/BaseShovelItem.java new file mode 100644 index 00000000..49ffeff8 --- /dev/null +++ b/src/main/java/ru/bclib/items/tool/BaseShovelItem.java @@ -0,0 +1,42 @@ +package ru.bclib.items.tool; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; +import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; +import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl; +import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl.Entry; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ShovelItem; +import net.minecraft.world.item.Tier; +import net.minecraft.world.level.block.state.BlockState; +import ru.bclib.client.models.ItemModelProvider; +import ru.bclib.client.models.ModelsHelper; + +public class BaseShovelItem extends ShovelItem implements DynamicAttributeTool, ItemModelProvider { + public BaseShovelItem(Tier material, float attackDamage, float attackSpeed, Properties settings) { + super(material, attackDamage, attackSpeed, settings); + } + + @Override + public int getMiningLevel(Tag tag, BlockState state, ItemStack stack, LivingEntity user) { + if (tag.equals(FabricToolTags.SHOVELS)) { + return this.getTier().getLevel(); + } + return 0; + } + + @Override + public float getDestroySpeed(ItemStack stack, BlockState state) { + Entry entry = ToolManagerImpl.entryNullable(state.getBlock()); + return (entry != null && entry.getMiningLevel(FabricToolTags.SHOVELS) >= 0) ? speed : super.getDestroySpeed(stack, state); + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return ModelsHelper.createHandheldItem(resourceLocation); + } +} diff --git a/src/main/java/ru/bclib/items/tool/BaseSwordItem.java b/src/main/java/ru/bclib/items/tool/BaseSwordItem.java new file mode 100644 index 00000000..c5807c12 --- /dev/null +++ b/src/main/java/ru/bclib/items/tool/BaseSwordItem.java @@ -0,0 +1,20 @@ +package ru.bclib.items.tool; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.SwordItem; +import net.minecraft.world.item.Tier; +import ru.bclib.client.models.ItemModelProvider; +import ru.bclib.client.models.ModelsHelper; + +public class BaseSwordItem extends SwordItem implements DynamicAttributeTool, ItemModelProvider { + public BaseSwordItem(Tier material, int attackDamage, float attackSpeed, Properties settings) { + super(material, attackDamage, attackSpeed, settings); + } + + @Override + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return ModelsHelper.createHandheldItem(resourceLocation); + } +} diff --git a/src/main/java/ru/bclib/registry/BaseBlockEntities.java b/src/main/java/ru/bclib/registry/BaseBlockEntities.java new file mode 100644 index 00000000..9afc79fb --- /dev/null +++ b/src/main/java/ru/bclib/registry/BaseBlockEntities.java @@ -0,0 +1,90 @@ +package ru.bclib.registry; + +import java.util.List; + +import com.google.common.collect.Lists; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import ru.bclib.BCLib; +import ru.bclib.blockentities.BaseBarrelBlockEntity; +import ru.bclib.blockentities.BaseChestBlockEntity; +import ru.bclib.blockentities.BaseFurnaceBlockEntity; +import ru.bclib.blockentities.BaseSignBlockEntity; +import ru.bclib.blocks.BaseBarrelBlock; +import ru.bclib.blocks.BaseChestBlock; +import ru.bclib.blocks.BaseFurnaceBlock; +import ru.bclib.blocks.BaseSignBlock; + +public class BaseBlockEntities { + public static final BlockEntityType CHEST = registerBlockEntity(BCLib.makeID("chest"), + BlockEntityType.Builder.of(BaseChestBlockEntity::new, getChests())); + public static final BlockEntityType BARREL = registerBlockEntity(BCLib.makeID("barrel"), + BlockEntityType.Builder.of(BaseBarrelBlockEntity::new, getBarrels())); + public static final BlockEntityType SIGN = registerBlockEntity(BCLib.makeID("sign"), + BlockEntityType.Builder.of(BaseSignBlockEntity::new, getSigns())); + public static final BlockEntityType FURNACE = registerBlockEntity(BCLib.makeID("furnace"), + BlockEntityType.Builder.of(BaseFurnaceBlockEntity::new, getFurnaces())); + + public static BlockEntityType registerBlockEntity(ResourceLocation blockId, BlockEntityType.Builder builder) { + return Registry.register(Registry.BLOCK_ENTITY_TYPE, blockId, builder.build(null)); + } + + public static void register() {} + + static Block[] getChests() { + List result = Lists.newArrayList(); + BaseRegistry.getModBlocks().forEach((item) -> { + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof BaseChestBlock) { + result.add(block); + } + } + }); + return result.toArray(new Block[] {}); + } + + static Block[] getBarrels() { + List result = Lists.newArrayList(); + BaseRegistry.getModBlocks().forEach((item) -> { + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof BaseBarrelBlock) { + result.add(block); + } + } + }); + return result.toArray(new Block[] {}); + } + + static Block[] getSigns() { + List result = Lists.newArrayList(); + BaseRegistry.getModBlocks().forEach((item) -> { + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof BaseSignBlock) { + result.add(block); + } + } + }); + return result.toArray(new Block[] {}); + } + + static Block[] getFurnaces() { + List result = Lists.newArrayList(); + BaseRegistry.getModBlocks().forEach((item) -> { + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof BaseFurnaceBlock) { + result.add(block); + } + } + }); + return result.toArray(new Block[] {}); + } +} diff --git a/src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java b/src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java new file mode 100644 index 00000000..5b8050ba --- /dev/null +++ b/src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java @@ -0,0 +1,15 @@ +package ru.bclib.registry; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry; +import ru.bclib.client.render.BaseChestBlockEntityRenderer; +import ru.bclib.client.render.BaseSignBlockEntityRenderer; + +@Environment(EnvType.CLIENT) +public class BaseBlockEntityRenders { + public static void register() { + BlockEntityRendererRegistry.INSTANCE.register(BaseBlockEntities.CHEST, BaseChestBlockEntityRenderer::new); + BlockEntityRendererRegistry.INSTANCE.register(BaseBlockEntities.SIGN, BaseSignBlockEntityRenderer::new); + } +} diff --git a/src/main/java/ru/bclib/registry/BaseRegistry.java b/src/main/java/ru/bclib/registry/BaseRegistry.java new file mode 100644 index 00000000..1a47fa56 --- /dev/null +++ b/src/main/java/ru/bclib/registry/BaseRegistry.java @@ -0,0 +1,50 @@ +package ru.bclib.registry; + +import com.google.common.collect.Lists; +import net.fabricmc.fabric.api.item.v1.FabricItemSettings; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.*; + +import java.util.List; + +public abstract class BaseRegistry { + protected static final List MOD_BLOCKS = Lists.newArrayList(); + protected static final List MOD_ITEMS = Lists.newArrayList(); + + public static void register() {} + + public static List getModBlocks() { + return MOD_BLOCKS; + } + + public static List getModItems() { + return MOD_ITEMS; + } + + protected final CreativeModeTab creativeTab; + + protected BaseRegistry(CreativeModeTab creativeTab) { + this.creativeTab = creativeTab; + } + + protected T register(String name, T obj) { + return register(createModId(name), obj); + } + + protected abstract T register(ResourceLocation objId, T obj); + + protected abstract ResourceLocation createModId(String name); + + protected void registerItem(ResourceLocation id, Item item, List registry) { + if (item != Items.AIR) { + Registry.register(Registry.ITEM, id, item); + registry.add(item); + } + } + + public FabricItemSettings makeItemSettings() { + FabricItemSettings properties = new FabricItemSettings(); + return (FabricItemSettings) properties.tab(creativeTab); + } +} diff --git a/src/main/java/ru/bclib/registry/BlocksRegistry.java b/src/main/java/ru/bclib/registry/BlocksRegistry.java new file mode 100644 index 00000000..7a75daa4 --- /dev/null +++ b/src/main/java/ru/bclib/registry/BlocksRegistry.java @@ -0,0 +1,49 @@ +package ru.bclib.registry; + +import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Item.Properties; +import net.minecraft.world.item.WaterLilyBlockItem; +import net.minecraft.world.level.block.Block; +import ru.bclib.interfaces.ISpetialItem; + +public abstract class BlocksRegistry extends BaseRegistry { + + protected BlocksRegistry(CreativeModeTab creativeTab) { + super(creativeTab); + } + + @Override + public Block register(ResourceLocation id, Block block) { + int maxCount = 64; + boolean placeOnWater = false; + if (block instanceof ISpetialItem) { + ISpetialItem item = (ISpetialItem) block; + maxCount = item.getStackSize(); + placeOnWater = item.canPlaceOnWater(); + } + Properties item = makeItemSettings().stacksTo(maxCount); + if (placeOnWater) { + registerBlockItem(id, new WaterLilyBlockItem(block, item)); + } else { + registerBlockItem(id, new BlockItem(block, item)); + } + if (block.defaultBlockState().getMaterial().isFlammable() && FlammableBlockRegistry.getDefaultInstance().get(block).getBurnChance() == 0) { + FlammableBlockRegistry.getDefaultInstance().add(block, 5, 5); + } + return Registry.register(Registry.BLOCK, id, block); + } + + public Block registerBlockOnly(String name, Block block) { + return Registry.register(Registry.BLOCK, createModId(name), block); + } + + public Item registerBlockItem(ResourceLocation id, Item item) { + registerItem(id, item, BaseRegistry.MOD_BLOCKS); + return item; + } +} diff --git a/src/main/java/ru/bclib/registry/ItemsRegistry.java b/src/main/java/ru/bclib/registry/ItemsRegistry.java new file mode 100644 index 00000000..8792d54d --- /dev/null +++ b/src/main/java/ru/bclib/registry/ItemsRegistry.java @@ -0,0 +1,111 @@ +package ru.bclib.registry; + +import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; +import net.minecraft.core.BlockSource; +import net.minecraft.core.Direction; +import net.minecraft.core.dispenser.DefaultDispenseItemBehavior; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.tags.Tag; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.food.FoodProperties; +import net.minecraft.world.item.*; +import net.minecraft.world.level.block.DispenserBlock; +import ru.bclib.items.BaseDrinkItem; +import ru.bclib.items.BaseSpawnEggItem; +import ru.bclib.items.EndDiscItem; +import ru.bclib.items.ModelProviderItem; +import ru.bclib.items.tool.BaseAxeItem; +import ru.bclib.items.tool.BaseHoeItem; +import ru.bclib.items.tool.BasePickaxeItem; +import ru.bclib.util.TagHelper; + +public abstract class ItemsRegistry extends BaseRegistry { + + protected ItemsRegistry(CreativeModeTab creativeTab) { + super(creativeTab); + } + + public Item registerDisc(String name, int power, SoundEvent sound) { + return register(name, new EndDiscItem(power, sound, makeItemSettings())); + } + + public Item registerItem(String name) { + return register(name, new ModelProviderItem(makeItemSettings())); + } + + @Override + public Item register(ResourceLocation itemId, Item item) { + if (item instanceof ArmorItem) { + return registerArmor(itemId, item); + } + registerItem(itemId, item, BaseRegistry.MOD_ITEMS); + return item; + } + + private Item registerArmor(ResourceLocation id, Item item) { + registerItem(id, item, BaseRegistry.MOD_ITEMS); + return item; + } + + public TieredItem registerTool(String name, TieredItem item) { + ResourceLocation id = createModId(name); + registerItem(id, item, BaseRegistry.MOD_ITEMS); + + if (item instanceof ShovelItem) { + TagHelper.addTag((Tag.Named) FabricToolTags.SHOVELS, item); + } else if (item instanceof SwordItem) { + TagHelper.addTag((Tag.Named) FabricToolTags.SWORDS, item); + } else if (item instanceof BasePickaxeItem) { + TagHelper.addTag((Tag.Named) FabricToolTags.PICKAXES, item); + } else if (item instanceof BaseAxeItem) { + TagHelper.addTag((Tag.Named) FabricToolTags.AXES, item); + } else if (item instanceof BaseHoeItem) { + TagHelper.addTag((Tag.Named) FabricToolTags.HOES, item); + } + + return item; + } + + public Item registerEgg(String name, EntityType type, int background, int dots) { + SpawnEggItem item = new BaseSpawnEggItem(type, background, dots, makeItemSettings()); + DefaultDispenseItemBehavior behavior = new DefaultDispenseItemBehavior() { + public ItemStack execute(BlockSource pointer, ItemStack stack) { + Direction direction = pointer.getBlockState().getValue(DispenserBlock.FACING); + EntityType entityType = ((SpawnEggItem) stack.getItem()).getType(stack.getTag()); + entityType.spawn(pointer.getLevel(), stack, null, pointer.getPos().relative(direction), MobSpawnType.DISPENSER, direction != Direction.UP, false); + stack.shrink(1); + return stack; + } + }; + DispenserBlock.registerBehavior(item, behavior); + return register(name, item); + } + + public Item registerFood(String name, int hunger, float saturation, MobEffectInstance... effects) { + FoodProperties.Builder builder = new FoodProperties.Builder().nutrition(hunger).saturationMod(saturation); + for (MobEffectInstance effect: effects) { + builder.effect(effect, 1F); + } + return registerFood(name, builder.build()); + } + + public Item registerFood(String name, FoodProperties foodComponent) { + return register(name, new ModelProviderItem(makeItemSettings().food(foodComponent))); + } + + public Item registerDrink(String name) { + return register(name, new BaseDrinkItem(makeItemSettings().stacksTo(1))); + } + + public Item registerDrink(String name, FoodProperties foodComponent) { + return register(name, new BaseDrinkItem(makeItemSettings().stacksTo(1).food(foodComponent))); + } + + public Item registerDrink(String name, int hunger, float saturation) { + FoodProperties.Builder builder = new FoodProperties.Builder().nutrition(hunger).saturationMod(saturation); + return registerDrink(name, builder.build()); + } +}