Fix issues with Insolator #25

Merged
BlakeRain merged 3 commits from BlakeRain/utamacraft:main into main 2023-12-03 17:30:53 +00:00
11 changed files with 168 additions and 511 deletions

View File

@ -56,7 +56,7 @@ mod_name=Utamacraft Mod
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT License
# The mod version. See https://semver.org/
mod_version=0.2.1-1.19
mod_version=0.2.2-1.19
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html

View File

@ -7,7 +7,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
@ -30,14 +29,14 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class InsolatorBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
private static VoxelShape SHAPE =
Block.box(0, 0, 0, 16, 16, 16);
private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 16, 16);
public InsolatorBlock() {
super(getProperties());
@ -45,15 +44,12 @@ public class InsolatorBlock extends BaseEntityBlock {
}
private static Block.Properties getProperties() {
return Block.Properties.of(Material.METAL)
.strength(6.0f)
.requiresCorrectToolForDrops()
.noOcclusion()
.lightLevel(state -> state.getValue(ACTIVE) ? 15 : 0);
return Block.Properties.of(Material.METAL).strength(6.0f).requiresCorrectToolForDrops().noOcclusion().lightLevel(state -> state.getValue(ACTIVE) ? 15 : 0);
}
@SuppressWarnings("deprecation")
@Override
public VoxelShape getShape(BlockState state, BlockGetter getter, BlockPos pos, CollisionContext context) {
public @NotNull VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter getter, @NotNull BlockPos pos, @NotNull CollisionContext context) {
return SHAPE;
}
@ -63,13 +59,15 @@ public class InsolatorBlock extends BaseEntityBlock {
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}
@SuppressWarnings("deprecation")
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
public @NotNull BlockState rotate(BlockState state, Rotation rotation) {
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
}
@SuppressWarnings("deprecation")
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
public @NotNull BlockState mirror(BlockState state, Mirror mirror) {
return state.rotate(mirror.getRotation(state.getValue(FACING)));
}
@ -78,18 +76,24 @@ public class InsolatorBlock extends BaseEntityBlock {
builder.add(FACING, ACTIVE);
}
@SuppressWarnings("deprecation")
@Override
public RenderShape getRenderShape(BlockState pState) {
public @NotNull RenderShape getRenderShape(@NotNull BlockState pState) {
return RenderShape.MODEL;
}
@SuppressWarnings("deprecation")
@Override
public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
public void onRemove(BlockState pState, @NotNull Level pLevel, @NotNull BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
if (!pState.is(pNewState.getBlock())) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if (blockEntity instanceof InsolatorBlockEntity insolator) {
if (pLevel instanceof ServerLevel) {
insolator.drops();
insolator.getInventoryOptional().ifPresent(handler -> {
for (int slot = 0; slot < handler.getSlots(); ++slot) {
Block.popResource(pLevel, pPos, handler.getStackInSlot(slot));
}
});
}
pLevel.updateNeighbourForOutputSignal(pPos, this);
@ -99,39 +103,46 @@ public class InsolatorBlock extends BaseEntityBlock {
super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving);
}
@SuppressWarnings("deprecation")
@Override
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) {
if (!pLevel.isClientSide()) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if (blockEntity instanceof InsolatorBlockEntity insolatorEntity) {
NetworkHooks.openScreen((ServerPlayer)pPlayer, insolatorEntity, pPos);
} else {
throw new IllegalStateException("Our container provider is missing");
}
public @NotNull InteractionResult use(@NotNull BlockState pState, @NotNull Level pLevel, @NotNull BlockPos pPos, @NotNull Player pPlayer, @NotNull InteractionHand pHand, @NotNull BlockHitResult pHit) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if (!(blockEntity instanceof InsolatorBlockEntity insolatorEntity)) {
return InteractionResult.PASS;
}
return InteractionResult.sidedSuccess(pLevel.isClientSide());
if (pLevel.isClientSide()) {
return InteractionResult.SUCCESS;
}
if (pPlayer instanceof ServerPlayer serverPlayer) {
NetworkHooks.openScreen(serverPlayer, insolatorEntity, pPos);
}
return InteractionResult.CONSUME;
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
return new InsolatorBlockEntity(pPos, pState);
public BlockEntity newBlockEntity(@NotNull BlockPos pPos, @NotNull BlockState pState) {
return ModBlockEntities.INSOLATOR.get().create(pPos, pState);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
return pLevel.isClientSide ? null : createTickerHelper(pBlockEntityType, ModBlockEntities.INSOLATOR.get(), InsolatorBlockEntity::serverTick);
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(@NotNull Level pLevel, @NotNull BlockState pState, @NotNull BlockEntityType<T> pBlockEntityType) {
if (pLevel.isClientSide()) {
return null;
}
return createTickerHelper(pBlockEntityType, ModBlockEntities.INSOLATOR.get(), InsolatorBlockEntity::serverTick);
}
@Override
public void animateTick(BlockState pState, Level pLevel, BlockPos pPos, RandomSource pRandom) {
public void animateTick(@NotNull BlockState pState, @NotNull Level pLevel, @NotNull BlockPos pPos, @NotNull RandomSource pRandom) {
if (pState.getValue(ACTIVE)) {
if (pRandom.nextDouble() < 1.0d) {
pLevel.playLocalSound(
pPos.getX() + 0.5, pPos.getY() + 0.5, pPos.getZ() + 0.5,
ModSounds.INSOLATOR.get(), SoundSource.BLOCKS, 0.1f, 1.0f, false);
pLevel.playLocalSound(pPos.getX() + 0.5, pPos.getY() + 0.5, pPos.getZ() + 0.5, ModSounds.INSOLATOR.get(), SoundSource.BLOCKS, 0.1f, 1.0f, false);
}
}
}

View File

@ -1,58 +1,49 @@
package net.banutama.utamacraft.block.entity;
import com.mojang.logging.LogUtils;
import net.banutama.utamacraft.block.custom.InsolatorBlock;
import net.banutama.utamacraft.networking.ModMessages;
import net.banutama.utamacraft.networking.packet.EnergySyncPacket;
import net.banutama.utamacraft.networking.packet.FluidSyncPacket;
import net.banutama.utamacraft.networking.packet.ItemStackSyncPacket;
import net.banutama.utamacraft.recipe.InsolatorRecipe;
import net.banutama.utamacraft.screen.InsolatorMenu;
import net.banutama.utamacraft.util.ModEnergyStorage;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.Containers;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer;
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.ContainerData;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
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.state.BlockState;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.energy.EnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import java.util.Optional;
public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, EnergySyncPacket.EnergySyncReceiver, FluidSyncPacket.FluidSyncReceiver, ItemStackSyncPacket.ItemStackSyncReceiver {
private static final Logger LOGGER = LogUtils.getLogger();
public class InsolatorBlockEntity extends BlockEntity implements MenuProvider {
public static final int ENERGY_REQUIRED = 32;
public static final int MAX_PROGRESS = 500;
private final ItemStackHandler itemHandler = new ItemStackHandler(3) {
private final ItemStackHandler inventory = new ItemStackHandler(3) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if (level != null && !level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncPacket(this, worldPosition));
}
super.onContentsChanged(slot);
InsolatorBlockEntity.this.sendUpdate();
}
@Override
@ -66,91 +57,36 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
}
};
@Override
public void receiveItemStack(NonNullList<ItemStack> stacks) {
for (int slot = 0; slot < stacks.size(); ++slot) {
itemHandler.setStackInSlot(slot, stacks.get(slot));
}
}
private static final int ENERGY_REQUIRED = 32;
private final ModEnergyStorage energyStorage = new ModEnergyStorage(60000, 256) {
private final ModEnergyStorage energy = new ModEnergyStorage(60000, 256) {
@Override
public void onEnergyChanged() {
setChanged();
ModMessages.sendToClients(new EnergySyncPacket(energy, capacity, getBlockPos()));
InsolatorBlockEntity.this.sendUpdate();
}
};
public IEnergyStorage getEnergyStorage() {
return this.energyStorage;
}
@Override
public void receiveEnergySync(int energy, int capacity) {
energyStorage.setEnergy(energy);
}
private final FluidTank fluidTank = new FluidTank(64000) {
private final FluidTank fluid = new FluidTank(64000) {
@Override
protected void onContentsChanged() {
setChanged();
if (level != null && !level.isClientSide()) {
ModMessages.sendToClients(new FluidSyncPacket(fluid, worldPosition));
}
InsolatorBlockEntity.this.sendUpdate();
}
@Override
public boolean isFluidValid(FluidStack stack) {
public boolean isFluidValid(@NotNull FluidStack stack) {
return stack.getFluid() == Fluids.WATER;
}
};
public FluidStack getFluidStack() {
return fluidTank.getFluid();
}
private final LazyOptional<ItemStackHandler> inventoryOptional = LazyOptional.of(() -> this.inventory);
private final LazyOptional<ModEnergyStorage> energyOptional = LazyOptional.of(() -> energy);
private final LazyOptional<FluidTank> fluidOptional = LazyOptional.of(() -> fluid);
@Override
public void receiveFluidSync(FluidStack fluid) {
fluidTank.setFluid(fluid);
}
private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty();
private LazyOptional<IEnergyStorage> lazyEnergyStorage = LazyOptional.empty();
private LazyOptional<IFluidHandler> lazyFluidHandler = LazyOptional.empty();
protected final ContainerData data;
private int progress = 0;
private int maxProgress = 500;
private boolean active = false;
public InsolatorBlockEntity(BlockPos pPos, BlockState pBlockState) {
super(ModBlockEntities.INSOLATOR.get(), pPos, pBlockState);
this.data = new ContainerData() {
@Override
public int get(int pIndex) {
return switch (pIndex) {
case 0 -> InsolatorBlockEntity.this.progress;
case 1 -> InsolatorBlockEntity.this.maxProgress;
case 2 -> InsolatorBlockEntity.this.active ? 1 : 0;
default -> 0;
};
}
@Override
public void set(int pIndex, int pValue) {
switch (pIndex) {
case 0 -> InsolatorBlockEntity.this.progress = pValue;
case 1 -> InsolatorBlockEntity.this.maxProgress = pValue;
case 2 -> InsolatorBlockEntity.this.active = pValue != 0;
}
}
@Override
public int getCount() {
return 3;
}
};
}
@Override
@ -161,76 +97,69 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
@Nullable
@Override
public AbstractContainerMenu createMenu(int pContainerId, @NotNull Inventory pPlayerInventory, @NotNull Player pPlayer) {
ModMessages.sendToClients(new EnergySyncPacket(this.energyStorage.getEnergyStored(), this.energyStorage.getMaxEnergyStored(), getBlockPos()));
ModMessages.sendToClients(new FluidSyncPacket(this.fluidTank.getFluid(), getBlockPos()));
return new InsolatorMenu(pContainerId, pPlayerInventory, this, this.data);
return new InsolatorMenu(pContainerId, pPlayerInventory, this);
}
@Override
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
if (cap == ForgeCapabilities.ENERGY) {
return lazyEnergyStorage.cast();
return energyOptional.cast();
}
if (cap == ForgeCapabilities.ITEM_HANDLER) {
return lazyItemHandler.cast();
return inventoryOptional.cast();
}
if (cap == ForgeCapabilities.FLUID_HANDLER) {
return lazyFluidHandler.cast();
return fluidOptional.cast();
}
return super.getCapability(cap, side);
}
@Override
public void onLoad() {
super.onLoad();
lazyItemHandler = LazyOptional.of(() -> itemHandler);
lazyEnergyStorage = LazyOptional.of(() -> energyStorage);
lazyFluidHandler = LazyOptional.of(() -> fluidTank);
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
lazyItemHandler.invalidate();
lazyEnergyStorage.invalidate();
lazyFluidHandler.invalidate();
inventoryOptional.invalidate();
energyOptional.invalidate();
fluidOptional.invalidate();
}
@Override
protected void saveAdditional(CompoundTag nbt) {
nbt.put("inventory", itemHandler.serializeNBT());
nbt.putInt("insolator.progress", progress);
nbt.putInt("insolator.energy", energyStorage.getEnergyStored());
fluidTank.writeToNBT(nbt);
protected void saveAdditional(@NotNull CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("inventory", inventory.serializeNBT());
nbt.put("fluid", fluid.writeToNBT(new CompoundTag()));
nbt.put("energy", energy.serializeNBT());
nbt.putInt("progress", progress);
nbt.putBoolean("active", active);
super.saveAdditional(nbt);
}
@Override
public void load(@NotNull CompoundTag nbt) {
super.load(nbt);
itemHandler.deserializeNBT(nbt.getCompound("inventory"));
progress = nbt.getInt("insolator.progress");
energyStorage.setEnergy(nbt.getInt("insolator.energy"));
fluidTank.readFromNBT(nbt);
inventory.deserializeNBT(nbt.getCompound("inventory"));
fluid.readFromNBT(nbt.getCompound("fluid"));
energy.deserializeNBT(nbt.get("energy"));
progress = nbt.getInt("progress");
active = nbt.getBoolean("active");
}
public void drops() {
SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots());
for (int slot = 0; slot < itemHandler.getSlots(); ++slot) {
inventory.setItem(slot, itemHandler.getStackInSlot(slot));
}
if (this.level != null) {
Containers.dropContents(this.level, this.worldPosition, inventory);
} else {
LOGGER.warn("Unable to drop inventory contents due to lack of level");
}
@Override
public @NotNull CompoundTag getUpdateTag() {
CompoundTag nbt = super.getUpdateTag();
saveAdditional(nbt);
return nbt;
}
public static void serverTick(Level level, BlockPos pos, BlockState state, InsolatorBlockEntity entity) {
@Nullable
@Override
public Packet<ClientGamePacketListener> getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
public static void serverTick(@NotNull Level level, BlockPos pos, BlockState state, InsolatorBlockEntity entity) {
if (level.isClientSide()) {
return;
}
@ -240,10 +169,10 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
if (entity.canCraft().isPresent() && entity.hasEnoughEnergy()) {
++entity.progress;
newActive = true;
entity.energyStorage.extractEnergy(ENERGY_REQUIRED, false);
entity.energy.extractEnergy(ENERGY_REQUIRED, false);
setChanged(level, pos, state);
if (entity.progress >= entity.maxProgress) {
if (entity.progress >= MAX_PROGRESS) {
entity.craftItem();
}
} else {
@ -258,24 +187,24 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
level.setBlock(pos, state, 3);
}
ItemStack fluid = entity.itemHandler.getStackInSlot(0);
ItemStack fluid = entity.inventory.getStackInSlot(0);
if (fluid.getCount() > 0) {
fluid.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresent(handler -> {
// Remove as much as we need, but no more than a bucket
int amount = Math.min(entity.fluidTank.getSpace(), 1000);
int amount = Math.min(entity.fluid.getSpace(), 1000);
// Simulate removal of that amount from the IFluidHandlerItem
FluidStack stack = handler.drain(amount, IFluidHandler.FluidAction.SIMULATE);
// Ensure that the fluid we would use is valid
if (entity.fluidTank.isFluidValid(stack)) {
if (entity.fluid.isFluidValid(stack)) {
// Remove the amount of fluid from the IFluidHandlerItem
stack = handler.drain(amount, IFluidHandler.FluidAction.EXECUTE);
// Fill our fluid tank with the fluid stack we drained from the IFluidHandlerItem
entity.fluidTank.fill(stack, IFluidHandler.FluidAction.EXECUTE);
entity.fluid.fill(stack, IFluidHandler.FluidAction.EXECUTE);
// Extract the current item from the fluid slot? TODO: Should this be when empty?
entity.itemHandler.extractItem(0, 1, false);
entity.itemHandler.insertItem(0, handler.getContainer(), false);
entity.inventory.extractItem(0, 1, false);
entity.inventory.insertItem(0, handler.getContainer(), false);
}
});
}
@ -292,15 +221,15 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
}
// Drain the amount of fluid specified in our recipe from the fluid tank
fluidTank.drain(recipe.get().getFluid().getAmount(), IFluidHandler.FluidAction.EXECUTE);
fluid.drain(recipe.get().getFluid().getAmount(), IFluidHandler.FluidAction.EXECUTE);
// Remove an item from the input slot.
itemHandler.extractItem(1, 1, false);
inventory.extractItem(1, 1, false);
// Insert the recipe output in to the output slot.
ItemStack output = itemHandler.getStackInSlot(2);
ItemStack output = inventory.getStackInSlot(2);
if (output.isEmpty()) {
itemHandler.setStackInSlot(2, recipe.get().getResultItem().copy());
inventory.setStackInSlot(2, recipe.get().getResultItem().copy());
} else {
output.grow(recipe.get().getResultItem().getCount());
}
@ -309,40 +238,34 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
}
private boolean hasEnoughEnergy() {
return energyStorage.getEnergyStored() >= ENERGY_REQUIRED * maxProgress;
return energy.getEnergyStored() >= ENERGY_REQUIRED * MAX_PROGRESS;
}
private Optional<InsolatorRecipe> canCraft() {
Optional<InsolatorRecipe> recipe = getRecipe();
if (recipe.isEmpty()) {
// LOGGER.info("Insolator cannot find recipe");
return Optional.empty();
}
// Make sure that the correct fluid is in the tank.
if (!fluidTank.getFluid().equals(recipe.get().getFluid())) {
// LOGGER.info("Insolator does not have correct fluid; contains {}, expected {}",
// fluidTank.getFluid().getFluid(), recipe.get().getFluid().getFluid());
if (!fluid.getFluid().equals(recipe.get().getFluid())) {
return Optional.empty();
}
// Ensure that we have enough fluid
if (fluidTank.getFluidAmount() < recipe.get().getFluid().getAmount()) {
// LOGGER.info("Insolator has {} of fluid; recipe requires {}", fluidTank.getFluidAmount(), recipe.get().getFluid().getAmount());
if (fluid.getFluidAmount() < recipe.get().getFluid().getAmount()) {
return Optional.empty();
}
ItemStack output = itemHandler.getStackInSlot(2);
ItemStack output = inventory.getStackInSlot(2);
// If the output isn't empty, and the item in the output is different to the output of the recipe, we cannot process.
if (!output.isEmpty() && output.getItem() != recipe.get().getResultItem().getItem()) {
// LOGGER.info("Cannot run insolator, as output item is not the same as the recipe output");
return Optional.empty();
}
// Make sure that the output is not saturated.
if (output.getCount() + recipe.get().getResultItem().getCount() > output.getMaxStackSize()) {
// LOGGER.info("Cannot run insolator, as output of {} items exceeds maximum of {}", output.getCount(), output.getMaxStackSize());
return Optional.empty();
}
@ -354,12 +277,40 @@ public class InsolatorBlockEntity extends BlockEntity implements MenuProvider, E
return Optional.empty();
}
SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots());
for (int slot = 0; slot < itemHandler.getSlots(); ++slot) {
inventory.setItem(slot, itemHandler.getStackInSlot(slot));
SimpleContainer inventory = new SimpleContainer(this.inventory.getSlots());
for (int slot = 0; slot < this.inventory.getSlots(); ++slot) {
inventory.setItem(slot, this.inventory.getStackInSlot(slot));
}
return level.getRecipeManager()
.getRecipeFor(InsolatorRecipe.Type.INSTANCE, inventory, level);
}
private void sendUpdate() {
setChanged();
if (this.level != null) {
this.level.sendBlockUpdated(this.worldPosition, getBlockState(), getBlockState(), Block.UPDATE_ALL);
}
}
public LazyOptional<ItemStackHandler> getInventoryOptional() {
return this.inventoryOptional;
}
public FluidTank getFluidTank() {
return this.fluid;
}
public EnergyStorage getEnergy() {
return this.energy;
}
public boolean getActive() {
return this.active;
}
public int getProgress() {
return this.progress;
}
}

View File

@ -1,14 +1,8 @@
package net.banutama.utamacraft.networking;
import net.banutama.utamacraft.Utamacraft;
import net.banutama.utamacraft.networking.packet.EnergySyncPacket;
import net.banutama.utamacraft.networking.packet.FluidSyncPacket;
import net.banutama.utamacraft.networking.packet.ItemStackSyncPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.PacketDistributor;
import net.minecraftforge.network.simple.SimpleChannel;
public class ModMessages {
@ -21,35 +15,5 @@ public class ModMessages {
.clientAcceptedVersions(s -> true)
.serverAcceptedVersions(s -> true)
.simpleChannel();
INSTANCE.messageBuilder(EnergySyncPacket.class, 0x0001, NetworkDirection.PLAY_TO_CLIENT)
.encoder(EnergySyncPacket::toBytes)
.decoder(EnergySyncPacket::new)
.consumerMainThread(EnergySyncPacket::handle)
.add();
INSTANCE.messageBuilder(FluidSyncPacket.class, 0x0002, NetworkDirection.PLAY_TO_CLIENT)
.encoder(FluidSyncPacket::toBytes)
.decoder(FluidSyncPacket::new)
.consumerMainThread(FluidSyncPacket::handle)
.add();
INSTANCE.messageBuilder(ItemStackSyncPacket.class, 0x0003, NetworkDirection.PLAY_TO_CLIENT)
.encoder(ItemStackSyncPacket::toBytes)
.decoder(ItemStackSyncPacket::new)
.consumerMainThread(ItemStackSyncPacket::handle)
.add();
}
public static <T> void sendToServer(T message) {
INSTANCE.sendToServer(message);
}
public static <T> void sendToPlayer(T message, ServerPlayer player) {
INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message);
}
public static <T> void sendToClients(T message) {
INSTANCE.send(PacketDistributor.ALL.noArg(), message);
}
}

View File

@ -1,11 +0,0 @@
package net.banutama.utamacraft.networking.packet;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public abstract class BasePacket {
public abstract void toBytes(FriendlyByteBuf buf);
public abstract boolean handle(Supplier<NetworkEvent.Context> supplier);
}

View File

@ -1,73 +0,0 @@
package net.banutama.utamacraft.networking.packet;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.network.NetworkEvent;
import org.jetbrains.annotations.NotNull;
import java.util.function.Supplier;
public class EnergySyncPacket extends BasePacket {
private final int energy;
private final int capacity;
private final BlockPos pos;
public EnergySyncPacket(int energy, int capacity, BlockPos pos) {
this.energy = energy;
this.capacity = capacity;
this.pos = pos;
}
public EnergySyncPacket(@NotNull FriendlyByteBuf buf) {
this.energy = buf.readInt();
this.capacity = buf.readInt();
this.pos = buf.readBlockPos();
}
@Override
public void toBytes(@NotNull FriendlyByteBuf buf) {
buf.writeInt(energy);
buf.writeInt(capacity);
buf.writeBlockPos(pos);
}
@Override
public boolean handle(@NotNull Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
Level level = Minecraft.getInstance().level;
if (level == null) {
return;
}
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof EnergySyncReceiver energyReceiver) {
energyReceiver.receiveEnergySync(energy, capacity);
Player player = Minecraft.getInstance().player;
if (player == null) {
return;
}
if (player.containerMenu instanceof EnergySyncReceiverMenu menu &&
menu.getBlockEntity().getBlockPos().equals(pos)) {
menu.receiveEnergySync(energy, capacity);
}
}
});
return true;
}
public interface EnergySyncReceiver {
void receiveEnergySync(int energy, int capacity);
}
public interface EnergySyncReceiverMenu extends EnergySyncReceiver {
BlockEntity getBlockEntity();
}
}

View File

@ -1,70 +0,0 @@
package net.banutama.utamacraft.networking.packet;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.network.NetworkEvent;
import org.jetbrains.annotations.NotNull;
import java.util.function.Supplier;
public class FluidSyncPacket extends BasePacket {
private final FluidStack fluid;
private final BlockPos pos;
public FluidSyncPacket(FluidStack fluid, BlockPos pos) {
this.fluid = fluid;
this.pos = pos;
}
public FluidSyncPacket(@NotNull FriendlyByteBuf buf) {
this.fluid = buf.readFluidStack();
this.pos = buf.readBlockPos();
}
@Override
public void toBytes(@NotNull FriendlyByteBuf buf) {
buf.writeFluidStack(fluid);
buf.writeBlockPos(pos);
}
@Override
public boolean handle(@NotNull Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
Level level = Minecraft.getInstance().level;
if (level == null) {
return;
}
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof FluidSyncReceiver fluidSyncReceiver) {
fluidSyncReceiver.receiveFluidSync(fluid.copy());
Player player = Minecraft.getInstance().player;
if (player == null) {
return;
}
if (player.containerMenu instanceof FluidSyncReceiverMenu menu &&
menu.getBlockEntity().getBlockPos().equals(pos)) {
menu.receiveFluidSync(fluid);
}
}
});
return true;
}
public interface FluidSyncReceiver {
void receiveFluidSync(FluidStack fluid);
}
public interface FluidSyncReceiverMenu extends FluidSyncReceiver {
BlockEntity getBlockEntity();
}
}

View File

@ -1,73 +0,0 @@
package net.banutama.utamacraft.networking.packet;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.network.NetworkEvent;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class ItemStackSyncPacket extends BasePacket {
private final NonNullList<ItemStack> stacks;
private final BlockPos pos;
public ItemStackSyncPacket(NonNullList<ItemStack> stacks, BlockPos pos) {
this.stacks = stacks;
this.pos = pos;
}
public ItemStackSyncPacket(IItemHandler handler, BlockPos pos) {
this.stacks = NonNullList.create();
for (int slot = 0; slot < handler.getSlots(); ++slot) {
this.stacks.add(handler.getStackInSlot(slot));
}
this.pos = pos;
}
public ItemStackSyncPacket(@NotNull FriendlyByteBuf buf) {
List<ItemStack> stacks = buf.readCollection(ArrayList::new, FriendlyByteBuf::readItem);
this.stacks = NonNullList.withSize(stacks.size(), ItemStack.EMPTY);
for (int slot = 0; slot < stacks.size(); ++slot) {
this.stacks.set(slot, stacks.get(slot));
}
this.pos = buf.readBlockPos();
}
@Override
public void toBytes(FriendlyByteBuf buf) {
buf.writeCollection(this.stacks, FriendlyByteBuf::writeItem);
buf.writeBlockPos(pos);
}
@Override
public boolean handle(@NotNull Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
Level level = Minecraft.getInstance().level;
if (level == null) {
return;
}
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof ItemStackSyncReceiver receiver) {
receiver.receiveItemStack(stacks);
}
});
return true;
}
public interface ItemStackSyncReceiver {
void receiveItemStack(NonNullList<ItemStack> handler);
}
}

View File

@ -1,47 +1,34 @@
package net.banutama.utamacraft.screen;
import com.mojang.logging.LogUtils;
import net.banutama.utamacraft.block.custom.ModBlocks;
import net.banutama.utamacraft.block.entity.InsolatorBlockEntity;
import net.banutama.utamacraft.networking.packet.EnergySyncPacket;
import net.banutama.utamacraft.networking.packet.FluidSyncPacket;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.*;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.items.SlotItemHandler;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
public class InsolatorMenu extends AbstractContainerMenu implements FluidSyncPacket.FluidSyncReceiverMenu, EnergySyncPacket.EnergySyncReceiverMenu {
private static final Logger LOGGER = LogUtils.getLogger();
import java.util.Objects;
public class InsolatorMenu extends AbstractContainerMenu {
public final InsolatorBlockEntity blockEntity;
private final Level level;
private final ContainerData data;
private FluidStack fluid;
private int energy = 0;
private int capacity = 0;
private final ContainerLevelAccess levelAccess;
public InsolatorMenu(int id, Inventory inventory, FriendlyByteBuf extraData) {
this(id, inventory, inventory.player.level.getBlockEntity(extraData.readBlockPos()), new SimpleContainerData(3));
this(id, inventory, inventory.player.level.getBlockEntity(extraData.readBlockPos()));
}
public InsolatorMenu(int id, Inventory inventory, BlockEntity entity, ContainerData data) {
public InsolatorMenu(int id, Inventory inventory, BlockEntity entity) {
super(ModMenuTypes.INSOLATOR_MENU.get(), id);
if (entity instanceof InsolatorBlockEntity insolator) {
checkContainerSize(inventory, 3);
this.level = inventory.player.level;
this.data = data;
this.levelAccess = ContainerLevelAccess.create(Objects.requireNonNull(entity.getLevel()), entity.getBlockPos());
this.blockEntity = insolator;
this.fluid = insolator.getFluidStack();
this.energy = insolator.getEnergyStorage().getEnergyStored();
this.capacity = insolator.getEnergyStorage().getMaxEnergyStored();
addPlayerInventory(inventory);
addPlayerHotbar(inventory);
@ -51,55 +38,18 @@ public class InsolatorMenu extends AbstractContainerMenu implements FluidSyncPac
this.addSlot(new SlotItemHandler(handler, 1, 86, 15));
this.addSlot(new SlotItemHandler(handler, 2, 86, 60));
});
addDataSlots(data);
} else {
throw new IllegalArgumentException("Block entity must be an InsolatorBlockEntity");
}
}
@Override
public void receiveFluidSync(FluidStack fluid) {
this.fluid = fluid;
}
@Override
public void receiveEnergySync(int energy, int capacity) {
this.energy = energy;
this.capacity = capacity;
}
@Override
public BlockEntity getBlockEntity() {
public InsolatorBlockEntity getBlockEntity() {
return blockEntity;
}
public FluidStack getFluid() {
return fluid;
}
public int getEnergy() {
return energy;
}
public int getEnergyCapacity() {
return capacity;
}
public boolean isCrafting() {
return data.get(2) == 1;
}
public float getScaledProgress() {
int progress = this.data.get(0);
int maxProgress = this.data.get(1);
return maxProgress != 0 && progress != 0 ? (float)progress / (float)maxProgress : 0;
}
@Override
public boolean stillValid(@NotNull Player player) {
return stillValid(ContainerLevelAccess.create(level, blockEntity.getBlockPos()), player, ModBlocks.INSOLATOR.get());
return stillValid(levelAccess, player, ModBlocks.INSOLATOR.get());
}
private static final int HOTBAR_SLOT_COUNT = 9;
@ -133,7 +83,6 @@ public class InsolatorMenu extends AbstractContainerMenu implements FluidSyncPac
return ItemStack.EMPTY;
}
} else {
LOGGER.error("Invalid slot index {}", index);
return ItemStack.EMPTY;
}

View File

@ -3,6 +3,7 @@ package net.banutama.utamacraft.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.banutama.utamacraft.Utamacraft;
import net.banutama.utamacraft.block.entity.InsolatorBlockEntity;
import net.banutama.utamacraft.screen.utils.FluidSprite;
import net.banutama.utamacraft.screen.utils.MouseUtils;
import net.banutama.utamacraft.screen.utils.TiledSprite;
@ -14,7 +15,9 @@ import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.energy.EnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@ -49,30 +52,34 @@ public class InsolatorScreen extends AbstractContainerScreen<InsolatorMenu> {
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
if (MouseUtils.isMouseOver(pMouseX, pMouseY, x + 32, y + 15, 11, 61)) {
List<Component> components = TooltipUtils.getFluidTooltip(menu.getFluid(), 64000);
FluidTank tank = menu.getBlockEntity().getFluidTank();
List<Component> components = TooltipUtils.getFluidTooltip(tank.getFluid(), 64000);
renderTooltip(pPoseStack, components, Optional.empty(),
pMouseX - x, pMouseY - y);
}
if (MouseUtils.isMouseOver(pMouseX, pMouseY, x + 45, y + 15, 11, 61)) {
List<Component> components = TooltipUtils.getEnergyTooltip(getMenu().getEnergy(), getMenu().getEnergyCapacity());
EnergyStorage energy = menu.getBlockEntity().getEnergy();
List<Component> components = TooltipUtils.getEnergyTooltip(energy.getEnergyStored(), energy.getMaxEnergyStored());
renderTooltip(pPoseStack, components, Optional.empty(), pMouseX - x, pMouseY - y);
}
}
private void renderEnergy(@NotNull PoseStack stack, int x, int y) {
if (menu.getEnergy() <= 0 || menu.getEnergyCapacity() <= 0) {
EnergyStorage energy = menu.getBlockEntity().getEnergy();
if (energy.getEnergyStored() <= 0 || energy.getMaxEnergyStored() <= 0) {
return;
}
final int ENERGY_HEIGHT = 60;
int stored = (int)(ENERGY_HEIGHT * ((float)menu.getEnergy() / (float)menu.getEnergyCapacity()));
int stored = (int)(ENERGY_HEIGHT * ((float)energy.getEnergyStored() / (float)energy.getMaxEnergyStored()));
fillGradient(stack, x, y + (ENERGY_HEIGHT - stored), x + 9, y + 60, 0xffb51500, 0xff600b00);
}
private void renderFluid(@NotNull PoseStack stack, int x, int y) {
FluidStack fluid = menu.getFluid();
FluidStack fluid = menu.getBlockEntity().getFluidTank().getFluid();
if (fluid.getFluid().isSame(Fluids.EMPTY)) {
return;
}
@ -96,13 +103,14 @@ public class InsolatorScreen extends AbstractContainerScreen<InsolatorMenu> {
}
private void renderProgressArrow(PoseStack stack, int x, int y) {
if (menu.isCrafting()) {
blit(stack, x + 90, y + 33, 176, 0, 8, (int)(25.0f * menu.getScaledProgress()));
if (menu.getBlockEntity().getActive()) {
float ratio = (float)menu.getBlockEntity().getProgress() / (float)InsolatorBlockEntity.MAX_PROGRESS;
blit(stack, x + 90, y + 33, 176, 0, 8, (int)(25.0f * ratio));
}
}
private void renderBulb(PoseStack stack, int x, int y) {
if (menu.isCrafting()) {
if (menu.getBlockEntity().getActive()) {
blit(stack, x + 67, y + 38, 176, 25, 9, 14);
}
}

View File

@ -1,6 +1,7 @@
{
"homepage": "https://git.blakerain.com/bans-minecraft/utamacraft",
"1.19.2": {
"0.2.2-1.19": "Fix bugs with Insolator",
"0.2.1-1.19": "Fixed mixin bug",
"0.2.0-1.19": "Added insolator and fire pendant",
"0.1.1-1.19": "Fix player peripheral and add missing recipe",
@ -8,7 +9,7 @@
"0.0.1-1.19": "Initial release"
},
"promos": {
"1.19.2-latest": "0.2.1-1.19",
"1.19.2-recommended": "0.2.1-1.19"
"1.19.2-latest": "0.2.2-1.19",
"1.19.2-recommended": "0.2.2-1.19"
}
}