package lv.enes.mc.eris_alchemy.block.entity; import jakarta.annotation.Nonnull; import lv.enes.mc.eris_alchemy.Emc; import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.BlockEntities; import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.Blocks; import lv.enes.mc.eris_alchemy.client.ErisAlchemyClientRegistry; import lv.enes.mc.eris_alchemy.menu.ChestLikeMenu; import lv.enes.mc.eris_alchemy.menu.EnergyCondenserMenu; import lv.enes.mc.eris_alchemy.utils.ContainerOpenersCounterUtil; import lv.enes.mc.eris_alchemy.utils.SyncedValue.SyncedDouble; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; import net.minecraft.client.resources.model.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.quiltmc.loader.api.minecraft.ClientOnly; import java.util.stream.IntStream; public class EnergyCondenserEntity extends ChestLikeEntity implements EmcStorageEntity, ExtendedScreenHandlerFactory { private final static int WIDTH = 13; private final static int HEIGHT = 7; private final NonNullList items = NonNullList.withSize(WIDTH * HEIGHT + 1, ItemStack.EMPTY); public final SyncedDouble storedEmc = new SyncedDouble(0); public EnergyCondenserEntity(BlockPos pos, BlockState state) { super(BlockEntities.ENERGY_CONDENSER, pos, state); } @Nonnull @Override protected ChestLikeMenu createMenu(int syncId, Inventory playerInventory) { return new EnergyCondenserMenu(syncId, playerInventory, this); } @Nonnull @Override protected NonNullList getItems() { return items; } @Override public double getMaxEmc() { return Emc.get(items.get(0)).orElse(Double.POSITIVE_INFINITY); } @ClientOnly @Nonnull public Material getMaterial() { return ErisAlchemyClientRegistry.Materials.ENERGY_CONDENSER; } @Nonnull @Override protected Block getParent() { return Blocks.ENERGY_CONDENSER; } @Override public double getStoredEmc() { return storedEmc.getValue(); } public SyncedDouble getStoredEmcSyncer() { return storedEmc; } @Override public void load(CompoundTag nbt) { super.load(nbt); storedEmc.setValue(nbt.getDouble("stored_emc")); } @Override protected void saveAdditional(CompoundTag nbt) { super.saveAdditional(nbt); nbt.putDouble("stored_emc", storedEmc.getValue()); } public void setStoredEmc(double storedEmc) { this.storedEmc.setValue(storedEmc); setChanged(); } @Override public void tick(Level world, BlockPos pos, BlockState state) { super.tick(world, pos, state); if (world.isClientSide) { return; } var cost = getMaxEmc(); tryConsumeEmc(cost); tryCloneTemplate(cost); this.storedEmc.syncIfChanged(ContainerOpenersCounterUtil.getOpeners(openersCounter)); } @Override public void writeScreenOpeningData(ServerPlayer player, FriendlyByteBuf buf) { storedEmc.serialize(buf); } private void tryCloneTemplate(double cost) { if (cost > getStoredEmc()) { return; } var template = items.get(0); items.stream() .skip(1) // skip template .filter(stack -> ItemStack.isSameItemSameTags(template, stack)) .filter(stack -> stack.getCount() < getMaxStackSize() && stack.getCount() < stack.getMaxStackSize()) .findFirst() .ifPresentOrElse( stack -> { stack.setCount(stack.getCount() + 1); setStoredEmc(getStoredEmc() - cost); setChanged(); }, () -> IntStream.range(1, items.size()) .filter(i -> items.get(i).isEmpty()) .findFirst() .ifPresent(emptySlot -> { items.set(emptySlot, template.copyWithCount(1)); setStoredEmc(getStoredEmc() - cost); setChanged(); }) ); } private void tryConsumeEmc(double cost) { if (cost <= getStoredEmc()) { return; } var template = items.get(0); var sacrifice = items.stream() .skip(1) // skip the template .filter(stack -> !ItemStack.isSameItemSameTags(template, stack)) .flatMap(stack -> Emc.get(stack) .stream() .mapToObj(emcValue -> new StackEmcPair(stack, emcValue))) .findFirst(); sacrifice.ifPresent(pair -> { pair.stack.setCount(pair.stack.getCount() - 1); setStoredEmc(getStoredEmc() + pair.emc()); }); } private record StackEmcPair(ItemStack stack, double emc) {} }