From a56025fcc644e8f67782971878c9b4c53b188fef Mon Sep 17 00:00:00 2001
From: thedarkcolour <30441001+thedarkcolour@users.noreply.github.com>
Date: Sat, 13 Jan 2024 21:40:07 -0800
Subject: [PATCH] Fully implemented the mechanical hammer in code
---
.../exdeorum/block/MechanicalHammerBlock.java | 61 +++++
.../exdeorum/block/MechanicalSieveBlock.java | 4 +-
.../exdeorum/block/SieveBlock.java | 2 +-
.../AbstractMachineBlockEntity.java | 170 ++++++++++++
.../blockentity/AbstractSieveBlockEntity.java | 16 +-
.../MechanicalHammerBlockEntity.java | 244 ++++++++++++++++++
.../blockentity/MechanicalHammerMenu.java | 116 +++++++++
.../MechanicalSieveBlockEntity.java | 157 +++--------
.../blockentity/logic/SieveLogic.java | 7 +-
.../exdeorum/client/ClientHandler.java | 2 +
.../client/screen/MechanicalHammerScreen.java | 94 +++++++
.../client/screen/MechanicalSieveScreen.java | 12 +-
.../client/screen/RedstoneControlWidget.java | 12 +-
.../exdeorum/client/ter/SieveRenderer.java | 17 +-
.../compat/jei/ExDeorumJeiPlugin.java | 17 ++
.../compat/top/ExDeorumInfoProvider.java | 11 +-
.../exdeorum/config/EConfig.java | 8 +
.../thedarkcolour/exdeorum/data/English.java | 2 +
.../exdeorum/data/TranslationKeys.java | 2 +
.../exdeorum/loot/HammerLootModifier.java | 46 ++--
.../exdeorum/menu/AbstractMachineMenu.java | 121 +++++++++
.../exdeorum/menu/EContainerMenu.java | 31 ---
.../exdeorum/menu/MechanicalSieveMenu.java | 87 +------
.../network/ClientMessageHandler.java | 4 +-
.../exdeorum/recipe/RecipeUtil.java | 9 +
.../exdeorum/recipe/sieve/SieveRecipe.java | 2 +
.../exdeorum/registry/EBlockEntities.java | 2 +
.../exdeorum/registry/EBlocks.java | 2 +
.../exdeorum/registry/EItems.java | 2 +
.../exdeorum/registry/EMenus.java | 2 +
.../gui/container/mechanical_hammer.png | Bin 0 -> 3109 bytes
.../textures/item/empty_slot_hammer.png | Bin 0 -> 2854 bytes
32 files changed, 974 insertions(+), 288 deletions(-)
create mode 100644 src/main/java/thedarkcolour/exdeorum/block/MechanicalHammerBlock.java
create mode 100644 src/main/java/thedarkcolour/exdeorum/blockentity/AbstractMachineBlockEntity.java
create mode 100644 src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerBlockEntity.java
create mode 100644 src/main/java/thedarkcolour/exdeorum/blockentity/MechanicalHammerMenu.java
create mode 100644 src/main/java/thedarkcolour/exdeorum/client/screen/MechanicalHammerScreen.java
create mode 100644 src/main/java/thedarkcolour/exdeorum/menu/AbstractMachineMenu.java
delete mode 100644 src/main/java/thedarkcolour/exdeorum/menu/EContainerMenu.java
create mode 100644 src/main/resources/assets/exdeorum/textures/gui/container/mechanical_hammer.png
create mode 100644 src/main/resources/assets/exdeorum/textures/item/empty_slot_hammer.png
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 extends IGlobalLootModifier> 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 0000000000000000000000000000000000000000..3cc69158485c517b8d59912ccd2d61aa1703a417
GIT binary patch
literal 3109
zcmds3>0c9R60Qz(C!G!fR8Sz?ha4H?5>~kq4mrHChytPzkrBiZF(Sy_AZP$NR9G&N
zfQ$!%9LnebLO4{sQ4v8M4`du%7?BZ2yvR1}hnf8swtv;X>U!&`r>eT@!<#8suTVj#_`;S!<7vhYOs$!+Ap)@?rede1OJ0;_DU^fR-&-
z0URtXEvpE)paAC;potO|G_ata1?N~$%YqyRXlrX9W(cuRM>|j6y
z1GY0DoDRV#@cDcmkLT>{TtL840*(+6&wv^hTxLTX8(P`W!iJv};F1Cq;7~-szX&KK
zAdvx4IP9W?0g(*Y$$+gGxVpN!xVV(CpqLT@k{M8^09}gEsR&Xwbg-eF4JAw{Wx;M7
zzNbUI0`w?Cw<44gP{slg4%_H(jDR#8$_bD)HMLQNsi$;ruOsh*>SroFj_o#{eq509Ll_ami-qJ7q^qZac2@_{M-fi|j1Jjyd*
z4*DkIvonYaPo5F`|b<+{n)4A0(Z_eKVK!A_oG;Ur2L8Q2;J73UEWCZgZ)+ht#aYo;iKXwV!Cwurz)-&th8ZdTqe@u)AmO`AMI)v?NTF
z#mc_YwT@Y-&$^Y8d#g4YbS+9k9omGQX&zch!fKuC`ADPv-t+TbIkHJ)Sc<
zrM2~B+*!Z+p!3^qZ#;}m=wODMXf;<>H(Ze~-<46c)b?E9#kaqF7_<9fpW8Udpwk
z_YC<*DAJz`=!t%l*DH(8irYg;w-Ko?74ev5To)xTOtj5R$;q>QBjZdrhR+9
zxa7r33h;TEL~4gz#|lvHjCaVd(oH=Q`MsEdhCsDpYV02&>eHB|@!=SDxac;rsA6>m
zx=+EF5QmY4atA`mM`RON(*4ETUj$N7pEx?5^vovG4HGYzW>ZZjU@uNAK*}PoEoVvP!&E+
z0#m#IEsj|%zP}=Xw<4Li^hnOasjMCMu${C%kAgA(B{n7CExu_s@=u#3RcNv
zbn&|(iP{%AMg_a9(KS6Pg;YyOXT*w&8&@8R%F9>#B9F&rmNc#_h^mmNC1l{SS*4AE
z$D-;R)Fud}x2krpa+JG1qPO;iiQncZPfT3cR~E@Yq9<4-q!PLN3q}YLE{VPv$D}lW
zAf%U)_M;7;Dy5B_sVmZYI#LzgDHe5xj6BUs%&U{UhrQP(W>T%HCv^u+EjgUU0yLG(33SC!nmklxj-S-`#=
zQK?F)N@^j^Y>Q_h$7y_NXp6Ay>C5tl&$}uTtrs0qvz`!eAM(LRxXzuVcX2_<7D;{{o@yrK%O@}
z9uJRHE;_Y0cIA%Hybf$0&BwlP6|dTTTlm=t6CvUGhPMRSSvT-buddEbE&p+95N!kk
zdmc{OCkOH(=%x7J(7;a~xp#h>)ZhETV~Ix^qoz-@o@=Dke$n>j+_$-R
z6hVCWqUm9gEIZ4!)F|Fcj~C_-*vi>8?NpUK3_7j#CQiRhTYfW%Og@;Yzd!1_HKb7n
Y-cFewjlWi2psp9-<-W%4oQp8+Kh@hP@&Et;
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..621a616f9b4e56dc9e1c25f7fb85f771b9635271
GIT binary patch
literal 2854
zcmV+>3)%FEP)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000Uv
zX+uL$Nkc;*P;zf(X>4Tx07%E3mUmQC*A|D*y?1({%`gH|hTglt0MdJtUPWP;8DJ;_
z4l^{dA)*2iMMRn+NKnLp(NH8-M6nPQRImpm2q-ZaMN}+rM%Ih2ti1Q~^84egZ|$@9
zx%=$B&srA%lBX}1mj+7#kjfMAgFKw+5s^`J>;QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-A
zz9>Nv%ZWK*kqtikEV84R*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?%
zE8;ie*i;TP0{|3BY!`4?i6S-;F^L}%f`(o2L0Dz>ZZynda
zx(`h}FNp#{x{a}MR#uh~m%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJ
zr)Q)ySsc3IpNIG#2mW;)20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ
z7KzgM5l~}{fYfy=Kz{89C<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c#
zB`Ac>67n+__r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQH
zqKX(I48#TTN1~8;gpaI8ijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2w
zRf4KU9Y%GadQmq~W2jlwM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=g
zjj_UbVj?j~n6;P^%sxyT<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynE
zso>0T?zku%50{Utz#YMz!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~f
zge1ZyLM5SA?cA^NYNxAX$R>L=^W`U
z=_Q#=)*?HSqsRjC4stX30{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe
z3CZh{Gg5ddEh!f%rqp_=8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{
z7i7jM2t}RZLSa!hQyM83DHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T
z7cGTWN;^&)roCIDw8Uu%XUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo4
z0i~d)5U7x)uwUV#!pu_YQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21Q
zMwzDUsGOu+u6#y$T7{xwufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~
zTE1GF+Cz1MIzv5Pys-#cBCZ~;
zMXm#GGH#)6)ozd6)!Y-@Tijj2>R4y()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x(
zW?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)B
zP)E2$IF@OjS(EuDD=h0owsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2
zx4vhC`i6oH6B|7?9^ORQl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@>
z)Hd$6f$iqotG0hEVi#R4HYu(seqX{Wx%!RiH@;dd*9H0$NjB!N_E9`?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k
z9U46xbhx+Ks=4`y;*ru8xJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8No
zCm1JMf6)A)ww=;m)B$zmbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834B{
znNMeP&(57oKR0te;rw_{Owaub5f^Ut2KEkI^tpKXlKZ6#eNKI6FWX%{b;ah&$*YX3
zo!2a{b@W^GxBq1EQ~QABK*x2f>s>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)z
zk?4`pJM24CcT?`ZxR-fv;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F|
z_DjYu?mT-%DP~zdZD6*{hzpfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z
z!Kc(upZ)~{nDhK^CfpAI000J1OjJcxRaF200QCf)pa1{>0(4SNQ~v>mYqF)wI?L-2kIS`&H$MhDDBj^2Cs16