Fully implemented the mechanical hammer in code
This commit is contained in:
parent
aa66440e8c
commit
a56025fcc6
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState pState, BlockEntityType<T> type) {
|
||||
return type == EBlockEntities.MECHANICAL_HAMMER.get() && !level.isClientSide ? (BlockEntityTicker<T>) 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ public class MechanicalSieveBlock extends EBlock {
|
|||
@Nullable
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState pState, BlockEntityType<T> type) {
|
||||
return type == EBlockEntities.MECHANICAL_SIEVE.get() && !level.isClientSide ? (BlockEntityTicker<T>) new MechanicalSieveBlockEntity.ServerTicker() : null;
|
||||
return type == EBlockEntities.MECHANICAL_SIEVE.get() && !level.isClientSide ? (BlockEntityTicker<T>) 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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<M extends AbstractMachineBlockEntity<M>> 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<ItemHelper> capabilityInventory;
|
||||
private final LazyOptional<EnergyStorage> capabilityEnergy;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public AbstractMachineBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state, Function<M, ItemHelper> 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 <T> LazyOptional<T> getCapability(@Nonnull Capability<T> 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<M extends AbstractMachineBlockEntity<M>> implements BlockEntityTicker<M> {
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<MechanicalHammerBlockEntity> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<MechanicalHammerBlockEntity> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<MechanicalSieveBlockEntity> 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<ItemHelper> capabilityInventory;
|
||||
private final LazyOptional<EnergyStorage> 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 <T> LazyOptional<T> getCapability(@Nonnull Capability<T> 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<MechanicalSieveBlockEntity> {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<MechanicalHammerMenu> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,14 +40,12 @@ public class MechanicalSieveScreen extends AbstractContainerScreen<MechanicalSie
|
|||
public static final int RECIPE_CLICK_AREA_WIDTH = 21;
|
||||
public static final int RECIPE_CLICK_AREA_HEIGHT = 14;
|
||||
|
||||
private final MechanicalSieveMenu menu;
|
||||
@Nullable
|
||||
private RedstoneControlWidget redstoneControlWidget;
|
||||
|
||||
public MechanicalSieveScreen(MechanicalSieveMenu menu, Inventory playerInventory, Component title) {
|
||||
super(menu, playerInventory, title);
|
||||
|
||||
this.menu = menu;
|
||||
this.imageWidth = 176;
|
||||
this.imageHeight = 173;
|
||||
this.inventoryLabelY += 7;
|
||||
|
|
@ -57,7 +55,7 @@ public class MechanicalSieveScreen extends AbstractContainerScreen<MechanicalSie
|
|||
protected void init() {
|
||||
super.init();
|
||||
|
||||
this.redstoneControlWidget = new RedstoneControlWidget(this, BACKGROUND_TEXTURE, this.leftPos + 176, this.topPos + 3);
|
||||
this.redstoneControlWidget = new RedstoneControlWidget(this.menu, BACKGROUND_TEXTURE, this.leftPos + this.imageWidth, this.topPos + 3);
|
||||
addRenderableWidget(this.redstoneControlWidget);
|
||||
}
|
||||
|
||||
|
|
@ -73,12 +71,12 @@ public class MechanicalSieveScreen extends AbstractContainerScreen<MechanicalSie
|
|||
graphics.blit(BACKGROUND_TEXTURE, left, top, 0, 0, this.imageWidth, this.imageHeight);
|
||||
|
||||
// energy bar
|
||||
int energy = Mth.floor(54 * ((float) this.menu.prevSieveEnergy / EConfig.SERVER.mechanicalSieveEnergyStorage.get()));
|
||||
int energy = Mth.floor(54 * ((float) this.menu.prevEnergy / EConfig.SERVER.mechanicalSieveEnergyStorage.get()));
|
||||
graphics.blit(BACKGROUND_TEXTURE, left + 10, top + 22 + 54 - energy, this.imageWidth, 14 + 54 - energy, 12, energy);
|
||||
|
||||
// progress arrow
|
||||
int progress = Math.min(21, (int) (this.menu.sieve.getProgress() * 22));
|
||||
graphics.blit(BACKGROUND_TEXTURE, left + 51, top + 42, this.imageWidth, 0, progress, 14);
|
||||
int progress = Math.min(21, (int) (this.menu.machine.getLogic().getProgress() * 22));
|
||||
graphics.blit(BACKGROUND_TEXTURE, left + RECIPE_CLICK_AREA_POS_X, top + RECIPE_CLICK_AREA_POS_Y, this.imageWidth, 0, progress, 14);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -91,7 +89,7 @@ public class MechanicalSieveScreen extends AbstractContainerScreen<MechanicalSie
|
|||
int ry = my - this.topPos;
|
||||
|
||||
if (9 <= rx && rx < 23 && 21 <= ry && ry < 77) {
|
||||
var energyTooltip = Component.translatable(TranslationKeys.ENERGY).append(Component.translatable(TranslationKeys.FRACTION_DISPLAY, this.menu.prevSieveEnergy, EConfig.SERVER.mechanicalSieveEnergyStorage.get())).append(" FE");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import net.minecraft.network.chat.Component;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.menu.AbstractMachineMenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -46,7 +47,7 @@ public class RedstoneControlWidget implements GuiEventListener, NarratableEntry,
|
|||
};
|
||||
private static final Component REDSTONE_CONTROL_LABEL = Component.translatable(TranslationKeys.REDSTONE_CONTROL_LABEL);
|
||||
|
||||
private final MechanicalSieveScreen screen;
|
||||
private final AbstractMachineMenu<?> 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) {
|
||||
|
|
|
|||
|
|
@ -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<T extends AbstractSieveBlockEntity> implements BlockEntityRenderer<T> {
|
||||
public class SieveRenderer<T extends EBlockEntity & SieveLogic.Owner> implements BlockEntityRenderer<T> {
|
||||
public static final Map<Item, TextureAtlasSprite> 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<T extends AbstractSieveBlockEntity> 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);
|
||||
|
|
|
|||
|
|
@ -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<IGuiClickableArea> 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<Rect2i> getGuiExtraAreas(MechanicalHammerScreen containerScreen) {
|
||||
var widget = containerScreen.getRedstoneControlWidget();
|
||||
if (widget != null) {
|
||||
return widget.getJeiBounds();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <C extends Container, T extends Recipe<C>> void addRecipes(IRecipeRegistration registration, RecipeType<T> category, Supplier<net.minecraft.world.item.crafting.RecipeType<T>> type) {
|
||||
|
|
|
|||
|
|
@ -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<Component>();
|
||||
var style = info.defaultTextStyle().height(10);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<M extends AbstractMachineBlockEntity<M>> 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 extends AbstractMachineBlockEntity<M>> 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -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<MechanicalSieveBlockEntity> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Item> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<BlockEntityType<MechanicalSieveBlockEntity>> MECHANICAL_SIEVE = BLOCK_ENTITIES.register("mechanical_sieve", () -> BlockEntityType.Builder.of(MechanicalSieveBlockEntity::new, EBlocks.MECHANICAL_SIEVE.get()).build(null));
|
||||
public static final RegistryObject<BlockEntityType<MechanicalHammerBlockEntity>> MECHANICAL_HAMMER = BLOCK_ENTITIES.register("mechanical_hammer", () -> BlockEntityType.Builder.of(MechanicalHammerBlockEntity::new, EBlocks.MECHANICAL_HAMMER.get()).build(null));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,8 @@ public class EBlocks {
|
|||
public static final RegistryObject<SieveBlock> CRYSTALLIZED_SIEVE = registerSieve("crystallized_sieve", SoundType.GLASS);
|
||||
// Mechanical Sieve (todo add properties)
|
||||
public static final RegistryObject<MechanicalSieveBlock> MECHANICAL_SIEVE = BLOCKS.register("mechanical_sieve", () -> new MechanicalSieveBlock(of()));
|
||||
// Mechanical Hammer (todo add properties)
|
||||
public static final RegistryObject<MechanicalHammerBlock> MECHANICAL_HAMMER = BLOCKS.register("mechanical_hammer", () -> new MechanicalHammerBlock(of()));
|
||||
|
||||
// Lava Crucibles
|
||||
public static final RegistryObject<LavaCrucibleBlock> PORCELAIN_CRUCIBLE = registerLavaCrucible("porcelain_crucible", true, SoundType.STONE);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ public class EItems {
|
|||
public static final RegistryObject<BlockItem> CRYSTALLIZED_SIEVE = registerItemBlock(EBlocks.CRYSTALLIZED_SIEVE);
|
||||
// Mechanical Sieves
|
||||
public static final RegistryObject<BlockItem> MECHANICAL_SIEVE = registerItemBlock(EBlocks.MECHANICAL_SIEVE);
|
||||
public static final RegistryObject<BlockItem> MECHANICAL_HAMMER = registerItemBlock(EBlocks.MECHANICAL_HAMMER);
|
||||
|
||||
// Lava Crucibles
|
||||
public static final RegistryObject<BlockItem> 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());
|
||||
|
|
|
|||
|
|
@ -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<MenuType<?>> MENUS = DeferredRegister.create(Registries.MENU, ExDeorum.ID);
|
||||
|
||||
public static final RegistryObject<MenuType<MechanicalSieveMenu>> MECHANICAL_SIEVE = MENUS.register("mechanical_sieve", () -> new MenuType<>((IContainerFactory<MechanicalSieveMenu>) MechanicalSieveMenu::new, FeatureFlags.DEFAULT_FLAGS));
|
||||
public static final RegistryObject<MenuType<MechanicalHammerMenu>> MECHANICAL_HAMMER = MENUS.register("mechanical_hammer", () -> new MenuType<>((IContainerFactory<MechanicalHammerMenu>) MechanicalHammerMenu::new, FeatureFlags.DEFAULT_FLAGS));
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Loading…
Reference in New Issue
Block a user