diff --git a/src/main/java/thedarkcolour/exdeorum/block/MechanicalHammerBlock.java b/src/main/java/thedarkcolour/exdeorum/block/MechanicalHammerBlock.java new file mode 100644 index 00000000..08ac1d16 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/block/MechanicalHammerBlock.java @@ -0,0 +1,61 @@ +/* + * Ex Deorum + * Copyright (c) 2024 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.blockentity.MechanicalHammerBlockEntity; +import thedarkcolour.exdeorum.registry.EBlockEntities; + +public class MechanicalHammerBlock extends EBlock { + public MechanicalHammerBlock(Properties properties) { + super(properties, EBlockEntities.MECHANICAL_HAMMER); + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public BlockEntityTicker getTicker(Level level, BlockState pState, BlockEntityType type) { + return type == EBlockEntities.MECHANICAL_HAMMER.get() && !level.isClientSide ? (BlockEntityTicker) new MechanicalHammerBlockEntity.ServerTicker<>() : null; + } + + // todo creative drop and tooltip + + @Override + public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) { + if (!oldState.is(state.getBlock())) { + if (level.getBlockEntity(pos) instanceof MechanicalHammerBlockEntity hammer) { + hammer.checkPoweredState(level, pos); + } + } + } + + @Override + public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) { + if (level.getBlockEntity(pos) instanceof MechanicalHammerBlockEntity hammer) { + hammer.checkPoweredState(level, pos); + } + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/block/MechanicalSieveBlock.java b/src/main/java/thedarkcolour/exdeorum/block/MechanicalSieveBlock.java index da3e56c3..48f7ca4f 100644 --- a/src/main/java/thedarkcolour/exdeorum/block/MechanicalSieveBlock.java +++ b/src/main/java/thedarkcolour/exdeorum/block/MechanicalSieveBlock.java @@ -69,7 +69,7 @@ public class MechanicalSieveBlock extends EBlock { @Nullable @Override public BlockEntityTicker getTicker(Level level, BlockState pState, BlockEntityType type) { - return type == EBlockEntities.MECHANICAL_SIEVE.get() && !level.isClientSide ? (BlockEntityTicker) new MechanicalSieveBlockEntity.ServerTicker() : null; + return type == EBlockEntities.MECHANICAL_SIEVE.get() && !level.isClientSide ? (BlockEntityTicker) new MechanicalSieveBlockEntity.ServerTicker<>() : null; } @Override @@ -93,7 +93,7 @@ public class MechanicalSieveBlock extends EBlock { public void playerWillDestroy(Level level, BlockPos pos, BlockState pState, Player player) { if (!level.isClientSide && player.isCreative() && level.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) { if (level.getBlockEntity(pos) instanceof MechanicalSieveBlockEntity sieve) { - if (!sieve.getMesh().isEmpty()) { + if (!sieve.getLogic().getMesh().isEmpty()) { var stack = new ItemStack(this); BlockItem.setBlockEntityData(stack, EBlockEntities.MECHANICAL_SIEVE.get(), sieve.saveWithoutMetadata()); var itemEntity = new ItemEntity(level, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, stack); diff --git a/src/main/java/thedarkcolour/exdeorum/block/SieveBlock.java b/src/main/java/thedarkcolour/exdeorum/block/SieveBlock.java index 37efda92..b85ca338 100644 --- a/src/main/java/thedarkcolour/exdeorum/block/SieveBlock.java +++ b/src/main/java/thedarkcolour/exdeorum/block/SieveBlock.java @@ -57,7 +57,7 @@ public class SieveBlock extends EBlock { if (!level.isClientSide) { if (!state.is(newState.getBlock())) { if (level.getBlockEntity(pos) instanceof SieveBlockEntity sieve) { - var mesh = sieve.getMesh(); + var mesh = sieve.getLogic().getMesh(); if (!mesh.isEmpty()) { dropItem(level, pos, mesh); diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractMachineBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractMachineBlockEntity.java new file mode 100644 index 00000000..73072078 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractMachineBlockEntity.java @@ -0,0 +1,170 @@ +/* + * Ex Deorum + * Copyright (c) 2024 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.blockentity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.energy.EnergyStorage; +import net.minecraftforge.network.NetworkHooks; +import thedarkcolour.exdeorum.blockentity.helper.EnergyHelper; +import thedarkcolour.exdeorum.blockentity.helper.ItemHelper; +import thedarkcolour.exdeorum.client.screen.RedstoneControlWidget; + +import javax.annotation.Nonnull; +import java.util.function.Function; + +public abstract class AbstractMachineBlockEntity> extends EBlockEntity implements MenuProvider { + public final ItemHelper inventory; + public final EnergyHelper energy; + protected int redstoneMode; + // not saved to NBT + protected boolean hasRedstonePower; + + private final LazyOptional capabilityInventory; + private final LazyOptional capabilityEnergy; + + @SuppressWarnings("unchecked") + public AbstractMachineBlockEntity(BlockEntityType type, BlockPos pos, BlockState state, Function inventory, int maxEnergy) { + super(type, pos, state); + + this.inventory = inventory.apply((M) this); + this.energy = new EnergyHelper(maxEnergy); + + this.capabilityInventory = LazyOptional.of(() -> this.inventory); + this.capabilityEnergy = LazyOptional.of(() -> this.energy); + } + + @Override + protected void saveAdditional(CompoundTag nbt) { + super.saveAdditional(nbt); + + nbt.put("inventory", this.inventory.serializeNBT()); + nbt.putInt("energy", this.energy.getEnergyStored()); + nbt.putInt("redstoneMode", this.redstoneMode); + } + + @Override + public void load(CompoundTag nbt) { + super.load(nbt); + + this.inventory.deserializeNBT(nbt.getCompound("inventory")); + this.energy.setStoredEnergy(nbt.getInt("energy")); + this.redstoneMode = Mth.clamp(nbt.getInt("redstoneMode"), 0, 2); + } + + @Override + public void onLoad() { + checkPoweredState(this.level, this.worldPosition); + } + + public void checkPoweredState(Level level, BlockPos pos) { + this.hasRedstonePower = level.hasNeighborSignal(pos); + } + + public void setRedstoneMode(int redstoneMode) { + this.redstoneMode = redstoneMode; + } + + public int getRedstoneMode() { + return this.redstoneMode; + } + + + @SuppressWarnings("NullableProblems") + @Override + public LazyOptional getCapability(@Nonnull Capability cap, @javax.annotation.Nullable Direction side) { + if (cap == ForgeCapabilities.ENERGY) { + return this.capabilityEnergy.cast(); + } else if (cap == ForgeCapabilities.ITEM_HANDLER) { + return this.capabilityInventory.cast(); + } + + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + + this.capabilityEnergy.invalidate(); + this.capabilityInventory.invalidate(); + } + + @Override + public InteractionResult use(Level level, Player player, InteractionHand hand) { + if (player instanceof ServerPlayer serverPlayer) { + NetworkHooks.openScreen(serverPlayer, this, buffer -> { + buffer.writeBlockPos(getBlockPos()); + buffer.writeByte(this.redstoneMode); + }); + return InteractionResult.CONSUME; + } else { + return InteractionResult.SUCCESS; + } + } + + public boolean stillValid(Player player) { + if (this.level.getBlockEntity(this.worldPosition) != this) { + return false; + } else { + return player.distanceToSqr(this.worldPosition.getX() + 0.5, this.worldPosition.getY() + 0.5, this.worldPosition.getZ() + 0.5) <= 64.0; + } + } + protected abstract boolean isRunning(); + + protected abstract void tryStartRunning(); + + // Only called serverside + protected abstract void runMachineTick(); + + protected abstract int getEnergyConsumption(); + + public static class ServerTicker> implements BlockEntityTicker { + @Override + public void tick(Level level, BlockPos pos, BlockState state, M machine) { + if (machine.redstoneMode == RedstoneControlWidget.REDSTONE_MODE_IGNORED || ((machine.redstoneMode == RedstoneControlWidget.REDSTONE_MODE_UNPOWERED)) != machine.hasRedstonePower) { + var energyConsumption = machine.getEnergyConsumption(); + + if (machine.energy.getEnergyStored() >= energyConsumption) { + if (!machine.isRunning()) { + machine.tryStartRunning(); + } + if (machine.isRunning()) { + machine.energy.extractEnergy(energyConsumption, false); + machine.runMachineTick(); + } + } + } + } + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractSieveBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractSieveBlockEntity.java index a418163b..eb4bc286 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractSieveBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/AbstractSieveBlockEntity.java @@ -63,19 +63,9 @@ public abstract class AbstractSieveBlockEntity extends EBlockEntity implements S this.logic.loadNbt(nbt); } - // Used for rendering and for TOP - public ItemStack getMesh() { - return this.logic.getMesh(); - } - - // Used for rendering - public float getProgress() { - return this.logic.getProgress(); - } - - // Used for rendering - public ItemStack getContents() { - return this.logic.getContents(); + @Override + public SieveLogic getLogic() { + return this.logic; } @Override diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java new file mode 100644 index 00000000..bee00e16 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java @@ -0,0 +1,244 @@ +/* + * Ex Deorum + * Copyright (c) 2024 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.blockentity; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.blockentity.helper.ItemHelper; +import thedarkcolour.exdeorum.config.EConfig; +import thedarkcolour.exdeorum.data.TranslationKeys; +import thedarkcolour.exdeorum.loot.HammerLootModifier; +import thedarkcolour.exdeorum.recipe.RecipeUtil; +import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe; +import thedarkcolour.exdeorum.registry.EBlockEntities; +import thedarkcolour.exdeorum.tag.EItemTags; + +public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity { + private static final Component TITLE = Component.translatable(TranslationKeys.MECHANICAL_HAMMER_SCREEN_TITLE); + private static final int INPUT_SLOT = 0; + private static final int HAMMER_SLOT = 1; + private static final int OUTPUT_SLOT = 2; + public static final int TOTAL_PROGRESS = 10_000_000; + // process should take 320 ticks or 10 seconds with no efficiency + private static final int PROGRESS_INTERVAL = TOTAL_PROGRESS / 200; + public static final int NOT_RUNNING = -1; + + // an integer from 0 to 10,000,000 instead of a decimal number which is inaccurate and buggy + private int progress = -1; + private float efficiency; + + public MechanicalHammerBlockEntity(BlockPos pos, BlockState state) { + super(EBlockEntities.MECHANICAL_HAMMER.get(), pos, state, ItemHandler::new, EConfig.SERVER.mechanicalHammerEnergyStorage.get()); + } + + public static boolean isValidInput(ItemStack stack) { + return RecipeUtil.getHammerRecipe(stack.getItem()) != null; + } + + @Override + protected void saveAdditional(CompoundTag nbt) { + super.saveAdditional(nbt); + + nbt.putInt("progress", this.progress); + } + + @Override + public void load(CompoundTag nbt) { + super.load(nbt); + + this.progress = nbt.getInt("progress"); + onHammerChanged(); + } + + @Override + public Component getDisplayName() { + return TITLE; + } + + @Override + public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player pPlayer) { + return new MechanicalHammerMenu(containerId, playerInventory, this); + } + + @Override + protected boolean isRunning() { + return this.progress != NOT_RUNNING; + } + + @Override + protected void tryStartRunning() { + var input = this.inventory.getStackInSlot(INPUT_SLOT); + + if (!input.isEmpty() && !this.inventory.getStackInSlot(HAMMER_SLOT).isEmpty()) { + if (canFitResultIntoOutput(input) != null) { + this.progress = 0; + } + } + } + + @Nullable + private HammerRecipe canFitResultIntoOutput(ItemStack input) { + var output = this.inventory.getStackInSlot(OUTPUT_SLOT); + + if (output.isEmpty() || output.getCount() < output.getMaxStackSize()) { + var recipe = RecipeUtil.getHammerRecipe(input.getItem()); + + if (recipe != null && (output.isEmpty() || matchesStack(recipe.result, output))) { + return recipe; + } + } + + return null; + } + + private static boolean matchesStack(Item item, ItemStack stack) { + return !stack.hasTag() && item == stack.getItem(); + } + + @Override + protected void runMachineTick() { + var input = this.inventory.getStackInSlot(INPUT_SLOT); + + if (!input.isEmpty() && !this.inventory.getStackInSlot(HAMMER_SLOT).isEmpty()) { + this.progress += PROGRESS_INTERVAL * this.efficiency; + + if (this.progress >= TOTAL_PROGRESS) { + var recipe = canFitResultIntoOutput(input); + + if (recipe != null) { + @SuppressWarnings("DataFlowIssue") + LootContext ctx = RecipeUtil.emptyLootContext((ServerLevel) this.level); + var resultCount = recipe.resultAmount.getInt(ctx); + resultCount += HammerLootModifier.calculateFortuneBonus(this.inventory.getStackInSlot(HAMMER_SLOT), ctx.getRandom(), resultCount == 0); + var output = this.inventory.getStackInSlot(OUTPUT_SLOT); + if (output.isEmpty()) { + this.inventory.setStackInSlot(OUTPUT_SLOT, new ItemStack(recipe.result, resultCount)); + } else { + output.setCount(Math.min(output.getMaxStackSize(), resultCount + output.getCount())); + } + input.shrink(1); + damageHammer(ctx.getRandom()); + + setChanged(); + } + + this.progress = NOT_RUNNING; + } + } + } + + private void damageHammer(RandomSource rand) { + var hammer = this.inventory.getStackInSlot(HAMMER_SLOT); + + if (hammer.isDamageableItem()) { + + if (hammer.hurt(1, rand, null)) { + hammer.shrink(1); + + if (hammer.isEmpty()) { + this.inventory.setStackInSlot(HAMMER_SLOT, ItemStack.EMPTY); + } + } + } + } + + private void onHammerChanged() { + var hammer = this.inventory.getStackInSlot(HAMMER_SLOT); + if (hammer.isEmpty()) { + this.progress = NOT_RUNNING; + } + this.efficiency = 1f + hammer.getEnchantmentLevel(Enchantments.BLOCK_EFFICIENCY) * 0.17f; + } + + @Override + protected int getEnergyConsumption() { + return EConfig.SERVER.mechanicalHammerEnergyConsumption.get(); + } + + // The value synced to the client for rendering the arrow in GUI + public int getGuiProgress() { + return Math.round((float)(24 * this.progress) / TOTAL_PROGRESS); + } + + public void setGuiProgress(int guiProgress) { + this.progress = (guiProgress * TOTAL_PROGRESS) / 24; + } + + public int getProgress() { + return this.progress; + } + + public void setProgress(int progress) { + this.progress = progress; + } + + private static class ItemHandler extends ItemHelper { + private final MechanicalHammerBlockEntity hammer; + + public ItemHandler(MechanicalHammerBlockEntity hammer) { + super(3); + this.hammer = hammer; + } + + @Override + public boolean isItemValid(int slot, @NotNull ItemStack stack) { + if (slot == INPUT_SLOT) { + return RecipeUtil.getHammerRecipe(stack.getItem()) != null; + } else if (slot == HAMMER_SLOT) { + return stack.is(EItemTags.HAMMERS); + } else { + return false; + } + } + + @Override + public int getSlotLimit(int slot) { + return slot == HAMMER_SLOT ? 1 : super.getSlotLimit(slot); + } + + @Override + public boolean canMachineExtract(int slot) { + return slot == OUTPUT_SLOT; + } + + @Override + protected void onContentsChanged(int slot) { + if (slot == HAMMER_SLOT) { + this.hammer.onHammerChanged(); + } else if (slot == INPUT_SLOT) { + if (getStackInSlot(INPUT_SLOT).isEmpty()) { + this.hammer.progress = NOT_RUNNING; + } + } + } + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerMenu.java b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerMenu.java new file mode 100644 index 00000000..c7dfa2c2 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerMenu.java @@ -0,0 +1,116 @@ +/* + * Ex Deorum + * Copyright (c) 2024 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.blockentity; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.DataSlot; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.ItemStack; +import thedarkcolour.exdeorum.ExDeorum; +import thedarkcolour.exdeorum.menu.AbstractMachineMenu; +import thedarkcolour.exdeorum.registry.EMenus; +import thedarkcolour.exdeorum.tag.EItemTags; + +public class MechanicalHammerMenu extends AbstractMachineMenu { + private static final ResourceLocation EMPTY_SLOT_HAMMER = new ResourceLocation(ExDeorum.ID, "item/empty_slot_hammer"); + private static final int NUM_SLOTS = 3; + + public MechanicalHammerMenu(int containerId, Inventory playerInventory, FriendlyByteBuf data) { + this(containerId, playerInventory, (MechanicalHammerBlockEntity) readPayload(playerInventory, data)); + } + + public MechanicalHammerMenu(int containerId, Inventory playerInventory, MechanicalHammerBlockEntity machine) { + super(EMenus.MECHANICAL_HAMMER.get(), containerId, playerInventory, machine); + + // input slot + addSlot(machine.inventory.createSlot(0, 32, 35)); + // hammer slot + addSlot(machine.inventory.createSlot(1, 56, 35).setBackground(InventoryMenu.BLOCK_ATLAS, EMPTY_SLOT_HAMMER)); + // output slot + addSlot(machine.inventory.createSlot(2, 116, 35)); + + addPlayerSlots(playerInventory, 84); + + addDataSlot(new ProgressDataSlot()); + } + + @Override + public ItemStack quickMoveStack(Player player, int clickedSlot) { + var stack = ItemStack.EMPTY; + var slot = this.slots.get(clickedSlot); + + if (slot.hasItem()) { + var clickedStack = slot.getItem(); + stack = clickedStack.copy(); + + if (clickedSlot > 1 && clickedSlot <= NUM_SLOTS) { // moving out of output slots + if (!moveItemStackTo(clickedStack, NUM_SLOTS, PLAYER_SLOTS + NUM_SLOTS, true)) { + return ItemStack.EMPTY; + } + } else if (clickedSlot < 2) { // moving out of input/mesh slot + if (!moveItemStackTo(clickedStack, NUM_SLOTS, NUM_SLOTS + PLAYER_SLOTS, false)) { + return ItemStack.EMPTY; + } + } else if (MechanicalHammerBlockEntity.isValidInput(clickedStack)) { // attempting to move into input slot + if (!moveItemStackTo(clickedStack, 0, 1, false)) { + return ItemStack.EMPTY; + } + } else if (clickedStack.is(EItemTags.HAMMERS)) { // attempting to move into mesh slot + if (!moveItemStackTo(clickedStack, 1, 2, false)) { + return ItemStack.EMPTY; + } + } else if (clickedSlot < NUM_SLOTS + 27) { // attempting to move from inventory to hotbar + if (!moveItemStackTo(clickedStack, NUM_SLOTS + 27, NUM_SLOTS + PLAYER_SLOTS, false)) { + return ItemStack.EMPTY; + } + } else if (clickedSlot < NUM_SLOTS + PLAYER_SLOTS) { // attempting to move from hotbar to inventory + if (!moveItemStackTo(clickedStack, NUM_SLOTS, NUM_SLOTS + 27, false)) { + return ItemStack.EMPTY; + } + } + + if (clickedStack.isEmpty()) { + slot.set(ItemStack.EMPTY); + } + slot.setChanged(); + if (clickedStack.getCount() == stack.getCount()) { + return ItemStack.EMPTY; + } + slot.onTake(player, clickedStack); + broadcastChanges(); + } + + return stack; + } + + private class ProgressDataSlot extends DataSlot { + @Override + public int get() { + return MechanicalHammerMenu.this.machine.getGuiProgress(); + } + + @Override + public void set(int value) { + MechanicalHammerMenu.this.machine.setGuiProgress(value); + } + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalSieveBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalSieveBlockEntity.java index 3fdbca2e..37de00f4 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalSieveBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalSieveBlockEntity.java @@ -19,35 +19,19 @@ package thedarkcolour.exdeorum.blockentity; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.energy.EnergyStorage; import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.network.NetworkHooks; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import thedarkcolour.exdeorum.blockentity.helper.EnergyHelper; import thedarkcolour.exdeorum.blockentity.helper.ItemHelper; import thedarkcolour.exdeorum.blockentity.logic.SieveLogic; -import thedarkcolour.exdeorum.client.screen.RedstoneControlWidget; import thedarkcolour.exdeorum.config.EConfig; import thedarkcolour.exdeorum.data.TranslationKeys; import thedarkcolour.exdeorum.menu.MechanicalSieveMenu; @@ -55,107 +39,70 @@ import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.registry.EBlockEntities; import thedarkcolour.exdeorum.tag.EItemTags; -import javax.annotation.Nonnull; - -public class MechanicalSieveBlockEntity extends AbstractSieveBlockEntity implements MenuProvider { +public class MechanicalSieveBlockEntity extends AbstractMachineBlockEntity implements SieveLogic.Owner { private static final Component TITLE = Component.translatable(TranslationKeys.MECHANICAL_SIEVE_SCREEN_TITLE); private static final int INPUT_SLOT = 0; public static final int MESH_SLOT = 1; - public final ItemHelper inventory; - public final EnergyHelper energy; - private int redstoneMode; - // not saved to NBT - public boolean hasRedstonePower; - - private final LazyOptional capabilityInventory; - private final LazyOptional capabilityEnergy; + private final SieveLogic logic; public MechanicalSieveBlockEntity(BlockPos pos, BlockState state) { - super(EBlockEntities.MECHANICAL_SIEVE.get(), pos, state, owner -> new SieveLogic(owner, false, true)); + super(EBlockEntities.MECHANICAL_SIEVE.get(), pos, state, ItemHandler::new, EConfig.SERVER.mechanicalSieveEnergyStorage.get()); - this.inventory = new ItemHandler(22); - this.energy = new EnergyHelper(EConfig.SERVER.mechanicalSieveEnergyStorage.get()); - - this.capabilityInventory = LazyOptional.of(() -> this.inventory); - this.capabilityEnergy = LazyOptional.of(() -> this.energy); + this.logic = new SieveLogic(this, false, true); } @Override protected void saveAdditional(CompoundTag nbt) { super.saveAdditional(nbt); - nbt.put("inventory", this.inventory.serializeNBT()); - nbt.putInt("energy", this.energy.getEnergyStored()); - nbt.putInt("redstoneMode", this.redstoneMode); + this.logic.saveNbt(nbt); } @Override public void load(CompoundTag nbt) { super.load(nbt); - this.inventory.deserializeNBT(nbt.getCompound("inventory")); - this.energy.setStoredEnergy(nbt.getInt("energy")); - this.redstoneMode = Mth.clamp(nbt.getInt("redstoneMode"), 0, 2); + this.logic.loadNbt(nbt); } @Override - public void onLoad() { - checkPoweredState(this.level, this.worldPosition); + protected boolean isRunning() { + return !this.logic.getContents().isEmpty(); } @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { - if (player instanceof ServerPlayer serverPlayer) { - NetworkHooks.openScreen(serverPlayer, this, buffer -> { - buffer.writeBlockPos(getBlockPos()); - buffer.writeByte(this.redstoneMode); - }); - return InteractionResult.CONSUME; - } else { - return InteractionResult.SUCCESS; + protected void tryStartRunning() { + var input = this.inventory.getStackInSlot(INPUT_SLOT); + + if (this.logic.isValidInput(input)) { + this.logic.startSifting(AbstractSieveBlockEntity.singleCopy(input)); + input.shrink(1); } } - @Nonnull @Override - public LazyOptional getCapability(@Nonnull Capability cap, @javax.annotation.Nullable Direction side) { - if (cap == ForgeCapabilities.ENERGY) { - return this.capabilityEnergy.cast(); - } else if (cap == ForgeCapabilities.ITEM_HANDLER) { - return this.capabilityInventory.cast(); - } - - return super.getCapability(cap, side); + protected void runMachineTick() { + this.logic.sift(0.01f); } @Override - public void invalidateCaps() { - super.invalidateCaps(); - - this.capabilityEnergy.invalidate(); - this.capabilityInventory.invalidate(); + protected int getEnergyConsumption() { + return EConfig.SERVER.mechanicalSieveEnergyConsumption.get(); } - private void serverTick() { - if (this.redstoneMode == RedstoneControlWidget.REDSTONE_MODE_IGNORED || ((this.redstoneMode == RedstoneControlWidget.REDSTONE_MODE_UNPOWERED)) != this.hasRedstonePower) { - var energyConsumption = EConfig.SERVER.mechanicalSieveEnergyConsumption.get(); + @Override + public void writeVisualData(FriendlyByteBuf buffer) { + buffer.writeItem(this.logic.getMesh()); + buffer.writeFloat(this.logic.getProgress()); + buffer.writeItem(this.logic.getContents()); + } - if (this.energy.getEnergyStored() >= energyConsumption) { - if (this.logic.getContents().isEmpty()) { - var input = this.inventory.getStackInSlot(INPUT_SLOT); - - if (this.logic.isValidInput(input)) { - this.logic.startSifting(AbstractSieveBlockEntity.singleCopy(input)); - input.shrink(1); - } - } - if (!this.logic.getContents().isEmpty()) { - this.energy.extractEnergy(energyConsumption, false); - this.logic.sift(0.01f); - } - } - } + @Override + public void readVisualData(FriendlyByteBuf buffer) { + this.logic.setMesh(buffer.readItem(), false); + this.logic.setProgress(buffer.readFloat()); + this.logic.setContents(buffer.readItem()); } @Override @@ -205,43 +152,32 @@ public class MechanicalSieveBlockEntity extends AbstractSieveBlockEntity impleme return TITLE; } - @Nullable @Override public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player pPlayer) { return new MechanicalSieveMenu(containerId, playerInventory, this); } - public boolean stillValid(Player player) { - if (this.level.getBlockEntity(this.worldPosition) != this) { - return false; - } else { - return player.distanceToSqr(this.worldPosition.getX() + 0.5, this.worldPosition.getY() + 0.5, this.worldPosition.getZ() + 0.5) <= 64.0; - } - } - + @Override public SieveLogic getLogic() { return this.logic; } - public void setRedstoneMode(int redstoneMode) { - this.redstoneMode = redstoneMode; + @SuppressWarnings("DataFlowIssue") + @Override + public ServerLevel getServerLevel() { + return (ServerLevel) this.level; } - public int getRedstoneMode() { - return this.redstoneMode; - } + private static class ItemHandler extends ItemHelper { + private final MechanicalSieveBlockEntity sieve; - public void checkPoweredState(Level level, BlockPos pos) { - this.hasRedstonePower = level.hasNeighborSignal(pos); - } - - private class ItemHandler extends ItemHelper { - public ItemHandler(int size) { - super(size); + public ItemHandler(MechanicalSieveBlockEntity sieve) { + super(22); + this.sieve = sieve; } @Override - public boolean isItemValid(int slot, @NotNull ItemStack stack) { + public boolean isItemValid(int slot, ItemStack stack) { if (slot == INPUT_SLOT) { return !RecipeUtil.getSieveRecipes(getStackInSlot(1).getItem(), stack).isEmpty(); } else if (slot == MESH_SLOT) { @@ -264,20 +200,13 @@ public class MechanicalSieveBlockEntity extends AbstractSieveBlockEntity impleme @Override protected void onContentsChanged(int slot) { if (slot == MESH_SLOT) { - MechanicalSieveBlockEntity.this.logic.setMesh(MechanicalSieveBlockEntity.this.inventory.getStackInSlot(MESH_SLOT)); + this.sieve.logic.setMesh(this.sieve.inventory.getStackInSlot(MESH_SLOT)); } } @Override protected void onLoad() { - MechanicalSieveBlockEntity.this.logic.setMesh(MechanicalSieveBlockEntity.this.inventory.getStackInSlot(MESH_SLOT), false); - } - } - - public static class ServerTicker implements BlockEntityTicker { - @Override - public void tick(Level level, BlockPos pos, BlockState state, MechanicalSieveBlockEntity sieve) { - sieve.serverTick(); + this.sieve.logic.setMesh(this.sieve.inventory.getStackInSlot(MESH_SLOT), false); } } } diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java b/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java index f2a6780a..6eed7556 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/logic/SieveLogic.java @@ -27,14 +27,11 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.storage.loot.LootContext; -import net.minecraft.world.level.storage.loot.LootParams; import thedarkcolour.exdeorum.config.EConfig; import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe; import thedarkcolour.exdeorum.tag.EItemTags; -import java.util.Map; - public class SieveLogic { private final Owner owner; private final boolean saveMesh; @@ -80,7 +77,7 @@ public class SieveLogic { // Need epsilon because floating point decimals suck if (this.progress >= 1.0f - Mth.EPSILON) { var level = this.owner.getServerLevel(); - var context = new LootContext.Builder(new LootParams(level, Map.of(), Map.of(), 0)).create(null); + var context = RecipeUtil.emptyLootContext(level); var rand = level.random; var limitDrops = this.contents.getItem() == Items.MOSS_BLOCK && EConfig.SERVER.limitMossSieveDrops.get(); var handledAnyDrops = false; @@ -207,5 +204,7 @@ public class SieveLogic { boolean handleResultItem(ItemStack result, ServerLevel level, RandomSource rand); void markUpdated(); + + SieveLogic getLogic(); } } diff --git a/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java b/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java index 1e9a3062..6581ab5e 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java @@ -43,6 +43,7 @@ import net.minecraftforge.fml.event.config.ModConfigEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import thedarkcolour.exdeorum.ExDeorum; +import thedarkcolour.exdeorum.client.screen.MechanicalHammerScreen; import thedarkcolour.exdeorum.client.screen.MechanicalSieveScreen; import thedarkcolour.exdeorum.client.ter.BarrelRenderer; import thedarkcolour.exdeorum.client.ter.CrucibleRenderer; @@ -101,6 +102,7 @@ public class ClientHandler { event.enqueueWork(() -> { setRenderLayers(); MenuScreens.register(EMenus.MECHANICAL_SIEVE.get(), MechanicalSieveScreen::new); + MenuScreens.register(EMenus.MECHANICAL_HAMMER.get(), MechanicalHammerScreen::new); }); } diff --git a/src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalHammerScreen.java b/src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalHammerScreen.java new file mode 100644 index 00000000..e5b81434 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalHammerScreen.java @@ -0,0 +1,94 @@ +/* + * Ex Deorum + * Copyright (c) 2024 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.client.screen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Inventory; +import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.ExDeorum; +import thedarkcolour.exdeorum.blockentity.MechanicalHammerMenu; +import thedarkcolour.exdeorum.config.EConfig; +import thedarkcolour.exdeorum.data.TranslationKeys; + +public class MechanicalHammerScreen extends AbstractContainerScreen { + private static final ResourceLocation BACKGROUND_TEXTURE = new ResourceLocation(ExDeorum.ID, "textures/gui/container/mechanical_hammer.png"); + + public static final int RECIPE_CLICK_AREA_POS_X = 80; + public static final int RECIPE_CLICK_AREA_POS_Y = 34; + public static final int RECIPE_CLICK_AREA_WIDTH = 23; + public static final int RECIPE_CLICK_AREA_HEIGHT = 16; + + @Nullable + private RedstoneControlWidget redstoneControlWidget; + + public MechanicalHammerScreen(MechanicalHammerMenu menu, Inventory playerInventory, Component title) { + super(menu, playerInventory, title); + + this.imageWidth = 176; + this.imageHeight = 166; + } + + @Override + protected void init() { + super.init(); + + this.redstoneControlWidget = new RedstoneControlWidget(this.menu, BACKGROUND_TEXTURE, this.leftPos + this.imageWidth, this.topPos + 3); + addRenderableWidget(this.redstoneControlWidget); + } + + @Nullable + public RedstoneControlWidget getRedstoneControlWidget() { + return this.redstoneControlWidget; + } + + @Override + protected void renderBg(GuiGraphics graphics, float pPartialTick, int pMouseX, int pMouseY) { + int left = this.leftPos; + int top = this.topPos; + graphics.blit(BACKGROUND_TEXTURE, left, top, 0, 0, this.imageWidth, this.imageHeight); + + // energy bar + int energy = Mth.floor(54 * ((float) this.menu.prevEnergy / EConfig.SERVER.mechanicalSieveEnergyStorage.get())); + graphics.blit(BACKGROUND_TEXTURE, left + 10, top + 15 + 54 - energy, this.imageWidth, 16 + 54 - energy, 12, energy); + + // progress arrow + int progress = Math.min(23, this.menu.machine.getGuiProgress()); + graphics.blit(BACKGROUND_TEXTURE, left + RECIPE_CLICK_AREA_POS_X, top + RECIPE_CLICK_AREA_POS_Y, this.imageWidth, 0, progress, 16); + } + + @Override + public void render(GuiGraphics graphics, int mx, int my, float pPartialTick) { + renderBackground(graphics); + super.render(graphics, mx, my, pPartialTick); + renderTooltip(graphics, mx, my); + + int rx = mx - this.leftPos; + int ry = my - this.topPos; + + if (9 <= rx && rx < 23 && 14 <= ry && ry < 70) { + var energyTooltip = Component.translatable(TranslationKeys.ENERGY).append(Component.translatable(TranslationKeys.FRACTION_DISPLAY, this.menu.prevEnergy, EConfig.SERVER.mechanicalSieveEnergyStorage.get())).append(" FE"); + graphics.renderTooltip(Minecraft.getInstance().font, energyTooltip, mx, my); + } + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalSieveScreen.java b/src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalSieveScreen.java index d9a83842..cf084c5a 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalSieveScreen.java +++ b/src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalSieveScreen.java @@ -40,14 +40,12 @@ public class MechanicalSieveScreen extends AbstractContainerScreen screen; private final ResourceLocation texture; private final int posX; private final int posY; @@ -68,7 +69,7 @@ public class RedstoneControlWidget implements GuiEventListener, NarratableEntry, // Last time (from currentTimeMillis) this button was clicked, used in animation lerp private long lastClicked = -1L; - public RedstoneControlWidget(MechanicalSieveScreen screen, ResourceLocation texture, int posX, int posY) { + public RedstoneControlWidget(AbstractMachineMenu screen, ResourceLocation texture, int posX, int posY) { this.screen = screen; this.texture = texture; this.posX = posX; @@ -106,7 +107,7 @@ public class RedstoneControlWidget implements GuiEventListener, NarratableEntry, var font = Minecraft.getInstance().font; if (this.expanded) { - var redstoneMode = this.screen.getMenu().sieve.getRedstoneMode(); + var redstoneMode = this.screen.machine.getRedstoneMode(); graphics.blit(this.texture, this.posX, this.posY, this.expandedU, this.expandedV, this.expandedWidth, this.expandedHeight); for (int i = 0; i < 3; ++i) { graphics.blit(this.texture, this.buttonsPosX + (i * 19), this.buttonsPosY, (redstoneMode == i ? this.tabU + 16 : this.tabU), this.tabV + this.tabHeight, 16, 16); @@ -157,9 +158,10 @@ public class RedstoneControlWidget implements GuiEventListener, NarratableEntry, return false; } + @SuppressWarnings("DataFlowIssue") private void setRedstoneMode(int redstoneMode) { - this.screen.getMenu().clickMenuButton(Minecraft.getInstance().player, redstoneMode); - Minecraft.getInstance().gameMode.handleInventoryButtonClick(this.screen.getMenu().containerId, redstoneMode); + this.screen.clickMenuButton(Minecraft.getInstance().player, redstoneMode); + Minecraft.getInstance().gameMode.handleInventoryButtonClick(this.screen.containerId, redstoneMode); } private void drawPartialConfig(GuiGraphics graphics) { diff --git a/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java b/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java index 8812ae51..e21c909f 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java +++ b/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java @@ -23,31 +23,33 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; -import net.minecraftforge.registries.ForgeRegistries; -import thedarkcolour.exdeorum.blockentity.AbstractSieveBlockEntity; +import thedarkcolour.exdeorum.blockentity.EBlockEntity; +import thedarkcolour.exdeorum.blockentity.logic.SieveLogic; import thedarkcolour.exdeorum.client.RenderUtil; import java.util.HashMap; import java.util.Map; -public class SieveRenderer implements BlockEntityRenderer { +public class SieveRenderer implements BlockEntityRenderer { public static final Map MESH_TEXTURES = new HashMap<>(); @Override public void render(T sieve, float partialTicks, PoseStack stack, MultiBufferSource buffers, int light, int overlay) { - var contents = sieve.getContents(); + var logic = sieve.getLogic(); + var contents = logic.getContents(); if (!contents.isEmpty() && contents.getItem() instanceof BlockItem blockItem) { var block = blockItem.getBlock(); - var percentage = sieve.getProgress(); + var percentage = logic.getProgress(); var face = RenderUtil.getTopFace(block); face.renderFlatSpriteLerp(buffers, stack, percentage, 0xff, 0xff, 0xff, light, 1.0f, 15f, 13f); } - var mesh = sieve.getMesh(); + var mesh = logic.getMesh(); if (!mesh.isEmpty()) { var builder = buffers.getBuffer(RenderType.cutoutMipped()); @@ -57,7 +59,8 @@ public class SieveRenderer implements BlockE if (MESH_TEXTURES.containsKey(meshItem)) { meshSprite = MESH_TEXTURES.get(meshItem); } else { - ResourceLocation registryName = ForgeRegistries.ITEMS.getKey(meshItem); + @SuppressWarnings("deprecation") + ResourceLocation registryName = BuiltInRegistries.ITEM.getKey(meshItem); ResourceLocation textureLoc = registryName.withPrefix("item/mesh/"); meshSprite = RenderUtil.blockAtlas.getSprite(textureLoc); MESH_TEXTURES.put(meshItem, meshSprite); diff --git a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java index 604150a1..5c6f6d94 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/jei/ExDeorumJeiPlugin.java @@ -48,6 +48,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.ModList; import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.blockentity.LavaCrucibleBlockEntity; +import thedarkcolour.exdeorum.client.screen.MechanicalHammerScreen; import thedarkcolour.exdeorum.client.screen.MechanicalSieveScreen; import thedarkcolour.exdeorum.compat.GroupedSieveRecipe; import thedarkcolour.exdeorum.compat.ModIds; @@ -322,6 +323,22 @@ public class ExDeorumJeiPlugin implements IModPlugin { return List.of(); } }); + registration.addGuiContainerHandler(MechanicalHammerScreen.class, new IGuiContainerHandler<>() { + @Override + public Collection getGuiClickableAreas(MechanicalHammerScreen containerScreen, double mouseX, double mouseY) { + IGuiClickableArea clickableArea = IGuiClickableArea.createBasic(MechanicalHammerScreen.RECIPE_CLICK_AREA_POS_X, MechanicalHammerScreen.RECIPE_CLICK_AREA_POS_Y, MechanicalHammerScreen.RECIPE_CLICK_AREA_WIDTH, MechanicalHammerScreen.RECIPE_CLICK_AREA_HEIGHT, HAMMER); + return List.of(clickableArea); + } + + @Override + public List getGuiExtraAreas(MechanicalHammerScreen containerScreen) { + var widget = containerScreen.getRedstoneControlWidget(); + if (widget != null) { + return widget.getJeiBounds(); + } + return List.of(); + } + }); } private static > void addRecipes(IRecipeRegistration registration, RecipeType category, Supplier> type) { diff --git a/src/main/java/thedarkcolour/exdeorum/compat/top/ExDeorumInfoProvider.java b/src/main/java/thedarkcolour/exdeorum/compat/top/ExDeorumInfoProvider.java index 679e144f..85bce11f 100644 --- a/src/main/java/thedarkcolour/exdeorum/compat/top/ExDeorumInfoProvider.java +++ b/src/main/java/thedarkcolour/exdeorum/compat/top/ExDeorumInfoProvider.java @@ -80,14 +80,15 @@ public class ExDeorumInfoProvider implements IProbeInfoProvider { info.tank(crucible.getTank()); } } else if (te instanceof SieveBlockEntity sieve) { - if (!sieve.getContents().isEmpty()) { - info.text(CompoundText.create().style(TextStyleClass.LABEL).text("Progress: ").style(TextStyleClass.WARNING).text((Math.round(1000 * sieve.getProgress()) / 10) + "%")); + var logic = sieve.getLogic(); + if (!logic.getContents().isEmpty()) { + info.text(CompoundText.create().style(TextStyleClass.LABEL).text("Progress: ").style(TextStyleClass.WARNING).text((Math.round(1000 * logic.getProgress()) / 10) + "%")); } if (playerEntity.isShiftKeyDown()) { - var mesh = sieve.getMesh(); + var mesh = logic.getMesh(); info.horizontal(info.defaultLayoutStyle().spacing(10).alignment(ElementAlignment.ALIGN_CENTER)) - .item(sieve.getMesh(), info.defaultItemStyle().width(16).height(16)) - .text(CompoundText.create().info(sieve.getMesh().getDescriptionId())); + .item(mesh, info.defaultItemStyle().width(16).height(16)) + .text(CompoundText.create().info(mesh.getDescriptionId())); if (mesh.isEnchanted()) { var list = new ObjectArrayList(); var style = info.defaultTextStyle().height(10); diff --git a/src/main/java/thedarkcolour/exdeorum/config/EConfig.java b/src/main/java/thedarkcolour/exdeorum/config/EConfig.java index 86167f7f..95298e93 100644 --- a/src/main/java/thedarkcolour/exdeorum/config/EConfig.java +++ b/src/main/java/thedarkcolour/exdeorum/config/EConfig.java @@ -133,6 +133,8 @@ public class EConfig { public final BooleanValue allowWitchWaterEntityConversion; public final IntValue mechanicalSieveEnergyStorage; public final IntValue mechanicalSieveEnergyConsumption; + public final IntValue mechanicalHammerEnergyStorage; + public final IntValue mechanicalHammerEnergyConsumption; public Server(ForgeConfigSpec.Builder builder) { builder.comment("Server configuration for Ex Deorum").push("server"); @@ -179,6 +181,12 @@ public class EConfig { this.mechanicalSieveEnergyConsumption = builder .comment("The amount of FE/t a tick consumed by the mechanical sieve when sifting a block.") .defineInRange("mechanical_sieve_energy_consumption", 40, 0, Integer.MAX_VALUE); + this.mechanicalHammerEnergyStorage = builder + .comment("The maximum amount of FE the mechanical hammer can have in its energy storage.") + .defineInRange("mechanical_hammer_energy_storage", 40_000, 0, Integer.MAX_VALUE); + this.mechanicalHammerEnergyConsumption = builder + .comment("The amount of FE/t a tick consumed by the mechanical hammer when crushing a block.") + .defineInRange("mechanical_hammer_energy_consumption", 20, 0, Integer.MAX_VALUE); builder.pop(); } diff --git a/src/main/java/thedarkcolour/exdeorum/data/English.java b/src/main/java/thedarkcolour/exdeorum/data/English.java index 895cd19d..5becf370 100644 --- a/src/main/java/thedarkcolour/exdeorum/data/English.java +++ b/src/main/java/thedarkcolour/exdeorum/data/English.java @@ -78,6 +78,8 @@ class English { english.add(TranslationKeys.REDSTONE_CONTROL_MODES[RedstoneControlWidget.REDSTONE_MODE_POWERED], "Powered"); english.add(TranslationKeys.REDSTONE_CONTROL_LABEL, "Redstone Mode"); english.add(TranslationKeys.REDSTONE_CONTROL_MODE, "Mode: "); + english.add(TranslationKeys.MECHANICAL_HAMMER_SCREEN_TITLE, "Mechanical Hammer"); + english.add(TranslationKeys.MECHANICAL_HAMMER_SCREEN_TITLE, "Consuming %s FE/t"); english.addBlock(EBlocks.VEXING_ARCHWOOD_CRUCIBLE, "Vexing Archwood Crucible"); english.addBlock(EBlocks.CASCADING_ARCHWOOD_CRUCIBLE, "Cascading Archwood Crucible"); diff --git a/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java b/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java index 120d5a96..a74189fd 100644 --- a/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java +++ b/src/main/java/thedarkcolour/exdeorum/data/TranslationKeys.java @@ -80,4 +80,6 @@ public class TranslationKeys { }; public static final String REDSTONE_CONTROL_LABEL = "gui." + ExDeorum.ID + ".redstone_control.label"; public static final String REDSTONE_CONTROL_MODE = "gui." + ExDeorum.ID + ".redstone_control.mode"; + public static final String MECHANICAL_HAMMER_SCREEN_TITLE = ExDeorum.ID + ".container.mechanical_hammer"; + public static final String MACHINE_FE_PER_TICK = "gui." + ExDeorum.ID + ".machine_fe_per_tick"; } diff --git a/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java b/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java index e639fae8..2c71ca66 100644 --- a/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java +++ b/src/main/java/thedarkcolour/exdeorum/loot/HammerLootModifier.java @@ -21,6 +21,7 @@ package thedarkcolour.exdeorum.loot; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.util.RandomSource; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantments; @@ -56,22 +57,8 @@ public class HammerLootModifier extends LootModifier { // fortune handling; more likely to boost drops if there are none to begin with if (context.hasParam(LootContextParams.TOOL)) { - var stack = context.getParam(LootContextParams.TOOL); - var fortune = stack.getEnchantmentLevel(Enchantments.BLOCK_FORTUNE); - - if (fortune != 0) { - var chance = context.getRandom().nextFloat(); - - if (resultAmount == 0) { - if (chance < 0.06 * fortune) { - resultAmount++; - } - } else { - if (chance < 0.03 * fortune) { - resultAmount++; - } - } - } + var hammer = context.getParam(LootContextParams.TOOL); + resultAmount += calculateFortuneBonus(hammer, context.getRandom(), resultAmount == 0); } if (resultAmount > 0) { @@ -89,5 +76,32 @@ public class HammerLootModifier extends LootModifier { public Codec codec() { return CODEC; } + + /** + * Calculates the bonus number of drops for a hammer enchanted with fortune. + * @param hammer The hammer in question + * @param rand RNG + * @param zeroBaseDrops Whether there were no drops to begin with + * @return The additional number of drops, to be added to the number of base drops + */ + public static int calculateFortuneBonus(ItemStack hammer, RandomSource rand, boolean zeroBaseDrops) { + var fortune = hammer.getEnchantmentLevel(Enchantments.BLOCK_FORTUNE); + + if (fortune != 0) { + var chance = rand.nextFloat(); + + if (zeroBaseDrops) { + if (chance < 0.06f * fortune) { + return 1; + } + } else { + if (chance < 0.03f * fortune) { + return 1; + } + } + } + + return 0; + } } diff --git a/src/main/java/thedarkcolour/exdeorum/menu/AbstractMachineMenu.java b/src/main/java/thedarkcolour/exdeorum/menu/AbstractMachineMenu.java new file mode 100644 index 00000000..16f7a35f --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/menu/AbstractMachineMenu.java @@ -0,0 +1,121 @@ +/* + * Ex Deorum + * Copyright (c) 2024 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.menu; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +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.MenuType; +import net.minecraft.world.inventory.Slot; +import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.blockentity.AbstractMachineBlockEntity; +import thedarkcolour.exdeorum.network.NetworkHandler; + +public abstract class AbstractMachineMenu> extends AbstractContainerMenu { + protected static final int PLAYER_SLOTS = 36; // hotbar + inventory + + @Nullable + private final ServerPlayer player; + public final M machine; + + public int prevEnergy; + + protected AbstractMachineMenu(MenuType pMenuType, int pContainerId, Inventory playerInventory, M machine) { + super(pMenuType, pContainerId); + + this.machine = machine; + + if (playerInventory.player instanceof ServerPlayer serverPlayer) { + this.player = serverPlayer; + } else { + this.player = null; + } + } + + // todo find a better way to do this + @SuppressWarnings({"DataFlowIssue", "unchecked"}) + protected static > M readPayload(Inventory playerInventory, FriendlyByteBuf data) { + var machine = (M) playerInventory.player.level().getBlockEntity(data.readBlockPos()); + machine.setRedstoneMode(data.readByte()); + return machine; + } + + // Call after own slots have been added + protected final void addPlayerSlots(Inventory playerInventory, int startY) { + // Inventory + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 9; ++j) { + addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, startY + i * 18)); + } + } + // Hotbar + for (int k = 0; k < 9; ++k) { + addSlot(new Slot(playerInventory, k, 8 + k * 18, startY + 58)); + } + } + + // When the server sends a menu property message, the client handles the synced property here. + public void setClientProperty(int index, int value) { + if (index == 0) { + this.prevEnergy = value; + } + } + + @Override + public void broadcastChanges() { + super.broadcastChanges(); + + if (this.player != null) { + syncProperties(this.player); + } + } + + @Override + public void broadcastFullState() { + super.broadcastFullState(); + + if (this.player != null) { + syncProperties(this.player); + } + } + + protected void syncProperties(ServerPlayer player) { + if (this.prevEnergy != this.machine.energy.getEnergyStored()) { + this.prevEnergy = this.machine.energy.getEnergyStored(); + + NetworkHandler.sendMenuProperty(player, this.containerId, 0, this.prevEnergy); + } + } + + @Override + public boolean clickMenuButton(Player pPlayer, int id) { + if (0 <= id && id < 3) { + this.machine.setRedstoneMode(id); + return true; + } + return false; + } + + @Override + public boolean stillValid(Player player) { + return this.machine.stillValid(player); + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/menu/EContainerMenu.java b/src/main/java/thedarkcolour/exdeorum/menu/EContainerMenu.java deleted file mode 100644 index f298089b..00000000 --- a/src/main/java/thedarkcolour/exdeorum/menu/EContainerMenu.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Ex Deorum - * Copyright (c) 2024 thedarkcolour - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package thedarkcolour.exdeorum.menu; - -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.MenuType; - -public abstract class EContainerMenu extends AbstractContainerMenu { - protected EContainerMenu(MenuType pMenuType, int pContainerId) { - super(pMenuType, pContainerId); - } - - // When the server sends a menu property message, the client handles the synced property here. - public abstract void setClientProperty(int index, int value); -} diff --git a/src/main/java/thedarkcolour/exdeorum/menu/MechanicalSieveMenu.java b/src/main/java/thedarkcolour/exdeorum/menu/MechanicalSieveMenu.java index 056283cc..069ee579 100644 --- a/src/main/java/thedarkcolour/exdeorum/menu/MechanicalSieveMenu.java +++ b/src/main/java/thedarkcolour/exdeorum/menu/MechanicalSieveMenu.java @@ -20,38 +20,24 @@ package thedarkcolour.exdeorum.menu; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.blockentity.MechanicalSieveBlockEntity; -import thedarkcolour.exdeorum.network.NetworkHandler; import thedarkcolour.exdeorum.registry.EMenus; -public class MechanicalSieveMenu extends EContainerMenu { +public class MechanicalSieveMenu extends AbstractMachineMenu { private static final ResourceLocation EMPTY_SLOT_MESH = new ResourceLocation(ExDeorum.ID, "item/empty_slot_mesh"); private static final int NUM_SLOTS = 22; // input + mesh, 20 output slots - private static final int PLAYER_SLOTS = 36; // hotbar + inventory - - public final MechanicalSieveBlockEntity sieve; - @Nullable - private final ServerPlayer player; - - public int prevSieveEnergy; public MechanicalSieveMenu(int containerId, Inventory playerInventory, FriendlyByteBuf data) { - this(containerId, playerInventory, (MechanicalSieveBlockEntity) playerInventory.player.level().getBlockEntity(data.readBlockPos())); - this.sieve.setRedstoneMode(data.readByte()); + this(containerId, playerInventory, (MechanicalSieveBlockEntity) readPayload(playerInventory, data)); } public MechanicalSieveMenu(int containerId, Inventory playerInventory, MechanicalSieveBlockEntity sieve) { - super(EMenus.MECHANICAL_SIEVE.get(), containerId); - - this.sieve = sieve; + super(EMenus.MECHANICAL_SIEVE.get(), containerId, playerInventory, sieve); // input slot addSlot(sieve.inventory.createSlot(0, 26, 30)); @@ -63,54 +49,7 @@ public class MechanicalSieveMenu extends EContainerMenu { addSlot(sieve.inventory.createSlot(2 + r * 5 + c, 80 + c * 18, 15 + r * 18)); } } - // Player slots - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 9; ++j) { - addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 7 + 84 + i * 18)); - } - } - for (int k = 0; k < 9; ++k) { - addSlot(new Slot(playerInventory, k, 8 + k * 18, 149)); - } - - if (playerInventory.player instanceof ServerPlayer serverPlayer) { - this.player = serverPlayer; - } else { - this.player = null; - } - } - - @Override - public void broadcastChanges() { - super.broadcastChanges(); - - if (this.player != null) { - if (this.prevSieveEnergy != this.sieve.energy.getEnergyStored()) { - this.prevSieveEnergy = this.sieve.energy.getEnergyStored(); - - NetworkHandler.sendMenuProperty(this.player, this.containerId, 0, this.prevSieveEnergy); - } - } - } - - @Override - public void broadcastFullState() { - super.broadcastFullState(); - - if (this.player != null) { - if (this.prevSieveEnergy != this.sieve.energy.getEnergyStored()) { - this.prevSieveEnergy = this.sieve.energy.getEnergyStored(); - - NetworkHandler.sendMenuProperty(this.player, this.containerId, 0, this.prevSieveEnergy); - } - } - } - - @Override - public void setClientProperty(int index, int value) { - if (index == 0) { - this.prevSieveEnergy = value; - } + addPlayerSlots(playerInventory, 91); } @Override @@ -130,11 +69,11 @@ public class MechanicalSieveMenu extends EContainerMenu { if (!moveItemStackTo(clickedStack, NUM_SLOTS, NUM_SLOTS + PLAYER_SLOTS, false)) { return ItemStack.EMPTY; } - } else if (this.sieve.getLogic().isValidInput(clickedStack)) { // attempting to move into input slot + } else if (this.machine.getLogic().isValidInput(clickedStack)) { // attempting to move into input slot if (!moveItemStackTo(clickedStack, 0, 1, false)) { return ItemStack.EMPTY; } - } else if (this.sieve.getLogic().isValidMesh(clickedStack)) { // attempting to move into mesh slot + } else if (this.machine.getLogic().isValidMesh(clickedStack)) { // attempting to move into mesh slot if (!moveItemStackTo(clickedStack, 1, 2, false)) { return ItemStack.EMPTY; } @@ -161,18 +100,4 @@ public class MechanicalSieveMenu extends EContainerMenu { return stack; } - - @Override - public boolean clickMenuButton(Player player, int id) { - if (0 <= id && id < 3) { - this.sieve.setRedstoneMode(id); - return false; - } - return false; - } - - @Override - public boolean stillValid(Player player) { - return this.sieve.stillValid(player); - } } diff --git a/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java b/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java index a9658ac2..5b76fcdf 100644 --- a/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java @@ -23,7 +23,7 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.player.Player; import thedarkcolour.exdeorum.blockentity.EBlockEntity; import thedarkcolour.exdeorum.client.ClientHandler; -import thedarkcolour.exdeorum.menu.EContainerMenu; +import thedarkcolour.exdeorum.menu.AbstractMachineMenu; public class ClientMessageHandler { public static boolean isInVoidWorld; @@ -54,7 +54,7 @@ public class ClientMessageHandler { public static void handleMenuProperty(MenuPropertyMessage msg) { Player player = Minecraft.getInstance().player; - if (player != null && player.containerMenu instanceof EContainerMenu menu && menu.containerId == msg.containerId()) { + if (player != null && player.containerMenu instanceof AbstractMachineMenu menu && menu.containerId == msg.containerId()) { menu.setClientProperty(msg.index(), msg.value()); } } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java index 423d42b8..63fba00f 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java @@ -24,6 +24,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; import net.minecraft.world.Container; @@ -36,7 +37,9 @@ import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootDataType; +import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.providers.number.*; import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.fluids.FluidStack; @@ -55,6 +58,7 @@ import thedarkcolour.exdeorum.registry.ERecipeTypes; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Objects; public final class RecipeUtil { @@ -298,7 +302,12 @@ public final class RecipeUtil { } } + @SuppressWarnings("deprecation") public static boolean isTagEmpty(TagKey tag) { return BuiltInRegistries.ITEM.getTag(tag).map(set -> !set.iterator().hasNext()).orElse(PreferredOres.getPreferredOre(tag) == Items.AIR); } + + public static LootContext emptyLootContext(ServerLevel level) { + return new LootContext.Builder(new LootParams(level, Map.of(), Map.of(), 0)).create(null); + } } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/sieve/SieveRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/sieve/SieveRecipe.java index 8a272197..76a89d5c 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/sieve/SieveRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/sieve/SieveRecipe.java @@ -87,6 +87,7 @@ public class SieveRecipe extends ProbabilityRecipe { return new SieveRecipe(id, ingredient, mesh, result, resultAmount, byHandOnly); } + @SuppressWarnings("deprecation") @Override public @Nullable SieveRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { Ingredient ingredient = Ingredient.fromNetwork(buffer); @@ -96,6 +97,7 @@ public class SieveRecipe extends ProbabilityRecipe { return new SieveRecipe(id, ingredient, mesh, result, resultAmount, buffer.readBoolean()); } + @SuppressWarnings("deprecation") @Override public void toNetwork(FriendlyByteBuf buffer, SieveRecipe recipe) { recipe.getIngredient().toNetwork(buffer); diff --git a/src/main/java/thedarkcolour/exdeorum/registry/EBlockEntities.java b/src/main/java/thedarkcolour/exdeorum/registry/EBlockEntities.java index d8da56c8..07fb03fe 100644 --- a/src/main/java/thedarkcolour/exdeorum/registry/EBlockEntities.java +++ b/src/main/java/thedarkcolour/exdeorum/registry/EBlockEntities.java @@ -26,6 +26,7 @@ import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity; import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity; import thedarkcolour.exdeorum.blockentity.LavaCrucibleBlockEntity; +import thedarkcolour.exdeorum.blockentity.MechanicalHammerBlockEntity; import thedarkcolour.exdeorum.blockentity.MechanicalSieveBlockEntity; import thedarkcolour.exdeorum.blockentity.SieveBlockEntity; import thedarkcolour.exdeorum.blockentity.WaterCrucibleBlockEntity; @@ -156,4 +157,5 @@ public class EBlockEntities { EBlocks.CRYSTALLIZED_SIEVE.get() ).build(null)); public static final RegistryObject> MECHANICAL_SIEVE = BLOCK_ENTITIES.register("mechanical_sieve", () -> BlockEntityType.Builder.of(MechanicalSieveBlockEntity::new, EBlocks.MECHANICAL_SIEVE.get()).build(null)); + public static final RegistryObject> MECHANICAL_HAMMER = BLOCK_ENTITIES.register("mechanical_hammer", () -> BlockEntityType.Builder.of(MechanicalHammerBlockEntity::new, EBlocks.MECHANICAL_HAMMER.get()).build(null)); } diff --git a/src/main/java/thedarkcolour/exdeorum/registry/EBlocks.java b/src/main/java/thedarkcolour/exdeorum/registry/EBlocks.java index b300b0bf..905a4be7 100644 --- a/src/main/java/thedarkcolour/exdeorum/registry/EBlocks.java +++ b/src/main/java/thedarkcolour/exdeorum/registry/EBlocks.java @@ -121,6 +121,8 @@ public class EBlocks { public static final RegistryObject CRYSTALLIZED_SIEVE = registerSieve("crystallized_sieve", SoundType.GLASS); // Mechanical Sieve (todo add properties) public static final RegistryObject MECHANICAL_SIEVE = BLOCKS.register("mechanical_sieve", () -> new MechanicalSieveBlock(of())); + // Mechanical Hammer (todo add properties) + public static final RegistryObject MECHANICAL_HAMMER = BLOCKS.register("mechanical_hammer", () -> new MechanicalHammerBlock(of())); // Lava Crucibles public static final RegistryObject PORCELAIN_CRUCIBLE = registerLavaCrucible("porcelain_crucible", true, SoundType.STONE); diff --git a/src/main/java/thedarkcolour/exdeorum/registry/EItems.java b/src/main/java/thedarkcolour/exdeorum/registry/EItems.java index 03df6a7b..778ec879 100644 --- a/src/main/java/thedarkcolour/exdeorum/registry/EItems.java +++ b/src/main/java/thedarkcolour/exdeorum/registry/EItems.java @@ -225,6 +225,7 @@ public class EItems { public static final RegistryObject CRYSTALLIZED_SIEVE = registerItemBlock(EBlocks.CRYSTALLIZED_SIEVE); // Mechanical Sieves public static final RegistryObject MECHANICAL_SIEVE = registerItemBlock(EBlocks.MECHANICAL_SIEVE); + public static final RegistryObject MECHANICAL_HAMMER = registerItemBlock(EBlocks.MECHANICAL_HAMMER); // Lava Crucibles public static final RegistryObject PORCELAIN_CRUCIBLE = registerItemBlock(EBlocks.PORCELAIN_CRUCIBLE); @@ -365,6 +366,7 @@ public class EItems { output.accept(CRYSTALLIZED_SIEVE.get()); } output.accept(MECHANICAL_SIEVE.get()); + output.accept(MECHANICAL_HAMMER.get()); output.accept(PORCELAIN_CRUCIBLE.get()); output.accept(WARPED_CRUCIBLE.get()); diff --git a/src/main/java/thedarkcolour/exdeorum/registry/EMenus.java b/src/main/java/thedarkcolour/exdeorum/registry/EMenus.java index a8750394..f4d95353 100644 --- a/src/main/java/thedarkcolour/exdeorum/registry/EMenus.java +++ b/src/main/java/thedarkcolour/exdeorum/registry/EMenus.java @@ -25,10 +25,12 @@ import net.minecraftforge.network.IContainerFactory; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.RegistryObject; import thedarkcolour.exdeorum.ExDeorum; +import thedarkcolour.exdeorum.blockentity.MechanicalHammerMenu; import thedarkcolour.exdeorum.menu.MechanicalSieveMenu; public class EMenus { public static final DeferredRegister> MENUS = DeferredRegister.create(Registries.MENU, ExDeorum.ID); public static final RegistryObject> MECHANICAL_SIEVE = MENUS.register("mechanical_sieve", () -> new MenuType<>((IContainerFactory) MechanicalSieveMenu::new, FeatureFlags.DEFAULT_FLAGS)); + public static final RegistryObject> MECHANICAL_HAMMER = MENUS.register("mechanical_hammer", () -> new MenuType<>((IContainerFactory) MechanicalHammerMenu::new, FeatureFlags.DEFAULT_FLAGS)); } diff --git a/src/main/resources/assets/exdeorum/textures/gui/container/mechanical_hammer.png b/src/main/resources/assets/exdeorum/textures/gui/container/mechanical_hammer.png new file mode 100644 index 00000000..3cc69158 Binary files /dev/null and b/src/main/resources/assets/exdeorum/textures/gui/container/mechanical_hammer.png differ diff --git a/src/main/resources/assets/exdeorum/textures/item/empty_slot_hammer.png b/src/main/resources/assets/exdeorum/textures/item/empty_slot_hammer.png new file mode 100644 index 00000000..621a616f Binary files /dev/null and b/src/main/resources/assets/exdeorum/textures/item/empty_slot_hammer.png differ