diff --git a/src/main/java/gregtech/api/capability/GregtechDataCodes.java b/src/main/java/gregtech/api/capability/GregtechDataCodes.java index 56078a8e64f..6054957ac0a 100644 --- a/src/main/java/gregtech/api/capability/GregtechDataCodes.java +++ b/src/main/java/gregtech/api/capability/GregtechDataCodes.java @@ -140,6 +140,11 @@ public static int assignId() { public static final int UPDATE_ITEM_COUNT = assignId(); public static final int UPDATE_FLUID_AMOUNT = assignId(); + // Quantum Storage Controller + public static final int UPDATE_CONTROLLER_POS = assignId(); + public static final int REMOVE_CONTROLLER = assignId(); + public static final int LOCATE_CONTROLLER = assignId(); + // Detector Covers public static final int UPDATE_INVERTED = assignId(); diff --git a/src/main/java/gregtech/api/capability/IDualHandler.java b/src/main/java/gregtech/api/capability/IDualHandler.java new file mode 100644 index 00000000000..595efc6a9f2 --- /dev/null +++ b/src/main/java/gregtech/api/capability/IDualHandler.java @@ -0,0 +1,14 @@ +package gregtech.api.capability; + +import net.minecraftforge.items.IItemHandler; + +public interface IDualHandler { + + boolean hasFluidTanks(); + + boolean hasItemHandlers(); + + IMultipleTankHandler getFluidTanks(); + + IItemHandler getItemHandlers(); +} diff --git a/src/main/java/gregtech/api/capability/IQuantumController.java b/src/main/java/gregtech/api/capability/IQuantumController.java new file mode 100644 index 00000000000..f2e5d333a5a --- /dev/null +++ b/src/main/java/gregtech/api/capability/IQuantumController.java @@ -0,0 +1,34 @@ +package gregtech.api.capability; + +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.common.capabilities.ICapabilityProvider; + +// ICapabilityProvider is needed because getCapability is called in the quantum proxy against this interface +public interface IQuantumController extends ICapabilityProvider { + + /** + * Constructs the network upon placement and when storages are added/removed + *
+ */ + void rebuildNetwork(); + + /** + * Return whether this storage block can connect. Can be used to implement a maximum distance from controller for + * example. + */ + boolean canConnect(IQuantumStorage storage); + + BlockPos getPos(); + + IDualHandler getHandler(); + + boolean isPowered(); + + long getEnergyUsage(); + + int getCount(IQuantumStorage.Type type); + + long getTypeEnergy(IQuantumStorage storage); + + void updateHandler(); +} diff --git a/src/main/java/gregtech/api/capability/IQuantumStorage.java b/src/main/java/gregtech/api/capability/IQuantumStorage.java new file mode 100644 index 00000000000..8a60ca63bf9 --- /dev/null +++ b/src/main/java/gregtech/api/capability/IQuantumStorage.java @@ -0,0 +1,77 @@ +package gregtech.api.capability; + +import gregtech.api.cover.CoverableView; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; + +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; + +import org.jetbrains.annotations.Nullable; + +public interface IQuantumStorage extends CoverableView { + + Type getType(); + + void setConnected(IQuantumController controller); + + void setDisconnected(); + + BlockPos getControllerPos(); + + @Nullable + IQuantumController getQuantumController(); + + BlockPos getPos(); + + default boolean isConnected() { + // use controllerPos here because it is synced + // on both sides, where controller is not + return getControllerPos() != null; + } + + default void tryFindNetwork() { + for (EnumFacing facing : EnumFacing.VALUES) { + var offset = getPos().offset(facing); + var state = getWorld().getBlockState(offset); + if (state.getBlock().isAir(state, getWorld(), offset)) continue; + MetaTileEntity mte; + if (getNeighbor(facing) instanceof IGregTechTileEntity gtte) { + mte = gtte.getMetaTileEntity(); + } else { + continue; + } + + IQuantumController candidate = null; + if (mte instanceof IQuantumStoragestorage) { + if (storage.isConnected()) { + IQuantumController controller = storage.getQuantumController(); + if (controller != null && controller.canConnect(this)) { + candidate = controller; + } + } + } else if (mte instanceof IQuantumController quantumController) { + if (quantumController.canConnect(this)) { + candidate = quantumController; + } + } + if (candidate != null) { + candidate.rebuildNetwork(); + return; + } + } + } + + T getTypeValue(); + + enum Type { + + ITEM, + FLUID, + EXTENDER, + PROXY, + ENERGY; + + public static final Type[] VALUES = values(); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java b/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java index a834867fd1e..d4e059d713a 100644 --- a/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java @@ -15,7 +15,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; -import com.google.common.base.Preconditions; import org.lwjgl.input.Mouse; import java.util.Arrays; @@ -64,7 +63,6 @@ public ClickButtonWidget setDisplayFunction(Supplier displayFunction) { } public ClickButtonWidget setTooltipText(String tooltipText, Object... args) { - Preconditions.checkNotNull(tooltipText, "tooltipText"); this.tooltipText = tooltipText; this.tooltipArgs = args; return this; diff --git a/src/main/java/gregtech/client/renderer/handler/BlockPosHighlightRenderer.java b/src/main/java/gregtech/client/renderer/handler/BlockPosHighlightRenderer.java index df5f186744f..c4b1254beb2 100644 --- a/src/main/java/gregtech/client/renderer/handler/BlockPosHighlightRenderer.java +++ b/src/main/java/gregtech/client/renderer/handler/BlockPosHighlightRenderer.java @@ -19,22 +19,33 @@ public class BlockPosHighlightRenderer { private static BlockPos posHighLight; - private static long hlEndTime; + private static long duration; + private static long offset; + private static long start; public static void renderBlockBoxHighLight(BlockPos blockpos, long durTimeMillis) { posHighLight = blockpos; - hlEndTime = System.currentTimeMillis() + durTimeMillis; + duration = durTimeMillis; + offset = 1500; + start = System.currentTimeMillis(); + } + + public static void renderBlockBoxHighLight(BlockPos blockpos, long durTimeMillis, long offsetTimeMillis) { + posHighLight = blockpos; + duration = durTimeMillis; + offset = offsetTimeMillis; + start = System.currentTimeMillis(); } public static void renderWorldLastEvent(RenderWorldLastEvent evt) { if (posHighLight != null) { long time = System.currentTimeMillis(); - if (time > hlEndTime) { + if (time > duration + start) { posHighLight = null; - hlEndTime = 0; + duration = 0; return; } - if (((time / 500) & 1) == 0) { + if (time % offset >= offset / 2) { return; } EntityPlayerSP p = Minecraft.getMinecraft().player; diff --git a/src/main/java/gregtech/client/renderer/texture/Textures.java b/src/main/java/gregtech/client/renderer/texture/Textures.java index 8615691ba87..5d4664f999b 100644 --- a/src/main/java/gregtech/client/renderer/texture/Textures.java +++ b/src/main/java/gregtech/client/renderer/texture/Textures.java @@ -97,6 +97,32 @@ public class Textures { "casings/pipe/machine_casing_grate"); public static final SimpleOverlayRenderer HIGH_POWER_CASING = new SimpleOverlayRenderer( "casings/computer/high_power_casing"); + public static final SimpleOverlayRenderer QUANTUM_CASING = new SimpleOverlayRenderer( + "casings/quantum/quantum_casing"); + public static final SimpleOverlayRenderer QUANTUM_CONTROLLER_FRONT_INACTIVE = new SimpleOverlayRenderer( + "casings/quantum/controller_front_inactive"); + public static final SimpleOverlayRenderer QUANTUM_CONTROLLER_FRONT_ACTIVE = new SimpleOverlayRenderer( + "casings/quantum/controller_front_active"); + public static final SimpleOverlayRenderer QUANTUM_CONTROLLER_ACTIVE = new SimpleOverlayRenderer( + "casings/quantum/controller_active"); + public static final SimpleOverlayRenderer QUANTUM_CONTROLLER_INACTIVE = new SimpleOverlayRenderer( + "casings/quantum/controller_inactive"); + public static final SimpleOverlayRenderer QUANTUM_PROXY_INACTIVE = new SimpleOverlayRenderer( + "casings/quantum/proxy_inactive"); + public static final SimpleOverlayRenderer QUANTUM_PROXY_ACTIVE = new SimpleOverlayRenderer( + "casings/quantum/proxy_active"); + public static final SimpleOverlayRenderer QUANTUM_EXTENDER = new SimpleOverlayRenderer("casings/quantum/extender"); + public static final SimpleOverlayRenderer QUANTUM_EXTENDER_ACTIVE = new SimpleOverlayRenderer( + "casings/quantum/extender_active"); + + public static final SimpleOverlayRenderer QUANTUM_INDICATOR = new SimpleOverlayRenderer( + "casings/quantum/quantum_indicator_disconnected"); + + public static final SimpleOverlayRenderer QUANTUM_INDICATOR_CONNECTED = new SimpleOverlayRenderer( + "casings/quantum/quantum_indicator_connected"); + + public static final SimpleOverlayRenderer QUANTUM_INDICATOR_POWERED = new SimpleOverlayRenderer( + "casings/quantum/quantum_indicator_powered"); // Simple Sided Cube Renderers public static final SimpleSidedCubeRenderer STEAM_CASING_BRONZE = new SimpleSidedCubeRenderer( diff --git a/src/main/java/gregtech/client/renderer/texture/custom/QuantumStorageRenderer.java b/src/main/java/gregtech/client/renderer/texture/custom/QuantumStorageRenderer.java index 03c0dd5656c..6796e164b0b 100644 --- a/src/main/java/gregtech/client/renderer/texture/custom/QuantumStorageRenderer.java +++ b/src/main/java/gregtech/client/renderer/texture/custom/QuantumStorageRenderer.java @@ -2,13 +2,13 @@ import gregtech.api.gui.resources.TextTexture; import gregtech.api.metatileentity.ITieredMetaTileEntity; -import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.util.TextFormattingUtil; import gregtech.client.renderer.texture.Textures; import gregtech.client.renderer.texture.cube.SimpleSidedCubeRenderer.RenderSide; import gregtech.client.utils.RenderUtil; import gregtech.common.ConfigHolder; import gregtech.common.metatileentities.storage.MetaTileEntityQuantumChest; +import gregtech.common.metatileentities.storage.MetaTileEntityQuantumStorage; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; @@ -69,10 +69,10 @@ public void registerIcons(TextureMap textureMap) { .registerSprite(new ResourceLocation("gregtech:blocks/overlay/machine/overlay_screen_glass")); } - public void renderMachine(CCRenderState renderState, - Matrix4 translation, - IVertexOperation[] pipeline, - T mte) { + public & ITieredMetaTileEntity> void renderMachine(CCRenderState renderState, + Matrix4 translation, + IVertexOperation[] pipeline, + T mte) { EnumFacing frontFacing = mte.getFrontFacing(); int tier = mte.getTier(); Textures.renderFace(renderState, translation, pipeline, frontFacing, glassBox, glassTexture, @@ -81,6 +81,10 @@ public void renderMachine(CCR TextureAtlasSprite hullTexture = Textures.VOLTAGE_CASINGS[tier] .getSpriteOnSide(RenderSide.bySide(EnumFacing.NORTH)); + if (mte.isConnected()) { + hullTexture = Textures.QUANTUM_CASING.getParticleSprite(); + } + for (var facing : boxFacingMap.keySet()) { // do not render the box at the front face when "facing" is "frontFacing" if (facing == frontFacing) continue; diff --git a/src/main/java/gregtech/common/items/behaviors/TricorderBehavior.java b/src/main/java/gregtech/common/items/behaviors/TricorderBehavior.java index c33ded9b363..1045603125a 100644 --- a/src/main/java/gregtech/common/items/behaviors/TricorderBehavior.java +++ b/src/main/java/gregtech/common/items/behaviors/TricorderBehavior.java @@ -5,6 +5,8 @@ import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.capability.IElectricItem; import gregtech.api.capability.IEnergyContainer; +import gregtech.api.capability.IQuantumController; +import gregtech.api.capability.IQuantumStorage; import gregtech.api.capability.IWorkable; import gregtech.api.capability.impl.FluidTankList; import gregtech.api.items.metaitem.stats.IItemBehaviour; @@ -284,6 +286,30 @@ else if (metaTileEntity instanceof IDataInfoProvider) list.addAll(provider.getDataInfo()); } + // quantum storage + if (metaTileEntity instanceof IQuantumController quantumController) { + list.add(new TextComponentTranslation("behavior.tricorder.divider")); + long eut = quantumController.getEnergyUsage(); // eu per 10 ticks + int tier = GTUtility.getTierByVoltage(eut / 10); + list.add(new TextComponentTranslation("behavior.tricorder.quantum_controller.usage", + TextFormatting.RED + String.format("%.1f", eut / 10d) + TextFormatting.RESET, + GTValues.VNF[tier])); + var handler = quantumController.getHandler(); + list.add(new TextComponentTranslation("behavior.tricorder.quantum_controller.connected_items", + TextFormatting.RED.toString() + handler.getItemHandlers().getSlots())); + list.add(new TextComponentTranslation("behavior.tricorder.quantum_controller.connected_fluids", + TextFormatting.RED.toString() + handler.getFluidTanks().getTanks())); + } else if (metaTileEntity instanceof IQuantumStoragestorage) { + var qcontrollor = storage.getQuantumController(); + if (qcontrollor != null) { + long eut = qcontrollor.getTypeEnergy(storage); + + list.add(new TextComponentTranslation("behavior.tricorder.divider")); + list.add(new TextComponentTranslation("behavior.tricorder.quantum_storage.usage", + TextFormatting.RED + String.format("%.1f", eut / 10d))); + } + } + } else if (tileEntity instanceof IPipeTile) { // pipes need special name handling IPipeTile pipeTile = (IPipeTile) tileEntity; diff --git a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java index e2e2624f8cd..dbe94985456 100644 --- a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java +++ b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java @@ -124,6 +124,9 @@ import gregtech.common.metatileentities.storage.MetaTileEntityCreativeTank; import gregtech.common.metatileentities.storage.MetaTileEntityDrum; import gregtech.common.metatileentities.storage.MetaTileEntityQuantumChest; +import gregtech.common.metatileentities.storage.MetaTileEntityQuantumExtender; +import gregtech.common.metatileentities.storage.MetaTileEntityQuantumProxy; +import gregtech.common.metatileentities.storage.MetaTileEntityQuantumStorageController; import gregtech.common.metatileentities.storage.MetaTileEntityQuantumTank; import gregtech.common.metatileentities.storage.MetaTileEntityWorkbench; import gregtech.common.pipelike.fluidpipe.longdistance.MetaTileEntityLDFluidEndpoint; @@ -222,6 +225,9 @@ public class MetaTileEntities { public static final MetaTileEntityRotorHolder[] ROTOR_HOLDER = new MetaTileEntityRotorHolder[6]; // HV, EV, IV, LuV, ZPM, UV public static final MetaTileEntityMufflerHatch[] MUFFLER_HATCH = new MetaTileEntityMufflerHatch[GTValues.UV + 1]; // LV-UV public static final MetaTileEntityFusionReactor[] FUSION_REACTOR = new MetaTileEntityFusionReactor[3]; + public static MetaTileEntityQuantumStorageController QUANTUM_STORAGE_CONTROLLER; + public static MetaTileEntityQuantumProxy QUANTUM_STORAGE_PROXY; + public static MetaTileEntityQuantumExtender QUANTUM_STORAGE_EXTENDER; public static final MetaTileEntityQuantumChest[] QUANTUM_CHEST = new MetaTileEntityQuantumChest[10]; public static final MetaTileEntityQuantumTank[] QUANTUM_TANK = new MetaTileEntityQuantumTank[10]; public static final MetaTileEntityBuffer[] BUFFER = new MetaTileEntityBuffer[3]; @@ -977,6 +983,14 @@ public static void init() { PUMP[2] = registerMetaTileEntity(1532, new MetaTileEntityPump(gregtechId("pump.hv"), 3)); PUMP[3] = registerMetaTileEntity(1533, new MetaTileEntityPump(gregtechId("pump.ev"), 4)); + // Quantum Storage Network 1757 - 1759 + QUANTUM_STORAGE_CONTROLLER = registerMetaTileEntity(1757, + new MetaTileEntityQuantumStorageController(gregtechId("quantum_storage_controller"))); + QUANTUM_STORAGE_PROXY = registerMetaTileEntity(1758, + new MetaTileEntityQuantumProxy(gregtechId("quantum_storage_proxy"))); + QUANTUM_STORAGE_EXTENDER = registerMetaTileEntity(1759, + new MetaTileEntityQuantumExtender(gregtechId("quantum_storage_extender"))); + // Super / Quantum Chests, IDs 1560-1574 for (int i = 0; i < 5; i++) { String voltageName = GTValues.VN[i + 1].toLowerCase(); diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityEnergyHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityEnergyHatch.java index d18b5b63ed2..fd79fc8811d 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityEnergyHatch.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityEnergyHatch.java @@ -1,12 +1,17 @@ package gregtech.common.metatileentities.multi.multiblockpart; import gregtech.api.GTValues; +import gregtech.api.capability.GregtechDataCodes; import gregtech.api.capability.IEnergyContainer; +import gregtech.api.capability.IQuantumController; +import gregtech.api.capability.IQuantumStorage; import gregtech.api.capability.impl.EnergyContainerHandler; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.multiblock.IMultiblockAbilityPart; import gregtech.api.metatileentity.multiblock.MultiblockAbility; +import gregtech.api.util.GTUtility; +import gregtech.client.renderer.ICubeRenderer; import gregtech.client.renderer.texture.Textures; import gregtech.client.renderer.texture.cube.SimpleOverlayRenderer; import gregtech.client.utils.PipelineUtil; @@ -14,9 +19,13 @@ import net.minecraft.client.resources.I18n; import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import codechicken.lib.render.CCRenderState; @@ -25,15 +34,23 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.ref.WeakReference; import java.util.List; public class MetaTileEntityEnergyHatch extends MetaTileEntityMultiblockPart - implements IMultiblockAbilityPart { + implements IMultiblockAbilityPart, + IQuantumStorage { protected final boolean isExportHatch; protected final int amperage; protected final IEnergyContainer energyContainer; + /** not synced, server only. lazily initialized from pos */ + private WeakReference controller = new WeakReference<>(null); + + /** synced, server and client */ + private BlockPos controllerPos; + public MetaTileEntityEnergyHatch(ResourceLocation metaTileEntityId, int tier, int amperage, boolean isExportHatch) { super(metaTileEntityId, tier); this.isExportHatch = isExportHatch; @@ -197,4 +214,137 @@ public void doExplosion(float explosionPower) { super.doExplosion(explosionPower); } } + + @Override + public void onRemoval() { + if (!getWorld().isRemote && isConnected()) { + IQuantumController controller = getQuantumController(); + if (controller != null) controller.rebuildNetwork(); + } + } + + @Override + public void onPlacement(@Nullable EntityLivingBase placer) { + super.onPlacement(placer); + if (getWorld() == null || getWorld().isRemote || isExportHatch) + return; + + // add to the network if an adjacent block is part of a network + // use whatever we find first, merging networks is not supported + tryFindNetwork(); + } + + @Override + public Type getType() { + return Type.ENERGY; + } + + @Override + public ICubeRenderer getBaseTexture() { + if (isConnected()) { + return Textures.QUANTUM_CASING; + } + return super.getBaseTexture(); + } + + @Override + public void setConnected(IQuantumController controller) { + if (getWorld().isRemote) return; + if (isExportHatch) return; + + if (!controller.getPos().equals(controllerPos)) { + this.controller = new WeakReference<>(controller); + this.controllerPos = controller.getPos(); + writeCustomData(GregtechDataCodes.UPDATE_CONTROLLER_POS, buf -> buf.writeBlockPos(controllerPos)); + markDirty(); + } + } + + @Override + public void setDisconnected() { + if (getWorld().isRemote) return; + + controller.clear(); + controllerPos = null; + writeCustomData(GregtechDataCodes.REMOVE_CONTROLLER, buf -> {}); + markDirty(); + } + + @Override + public void receiveCustomData(int dataId, PacketBuffer buf) { + super.receiveCustomData(dataId, buf); + if (dataId == GregtechDataCodes.UPDATE_CONTROLLER_POS) { + this.controllerPos = buf.readBlockPos(); + this.controller.clear(); + scheduleRenderUpdate(); + } else if (dataId == GregtechDataCodes.REMOVE_CONTROLLER) { + this.controllerPos = null; + this.controller.clear(); + scheduleRenderUpdate(); + } + } + + @Override + public void writeInitialSyncData(PacketBuffer buf) { + super.writeInitialSyncData(buf); + buf.writeBoolean(controllerPos != null); + if (controllerPos != null) { + buf.writeBlockPos(controllerPos); + } + } + + @Override + public void receiveInitialSyncData(PacketBuffer buf) { + super.receiveInitialSyncData(buf); + if (buf.readBoolean()) { + controllerPos = buf.readBlockPos(); + scheduleRenderUpdate(); + } + } + + // use this to make sure controller is properly initialized + @Override + public final IQuantumController getQuantumController() { + if (isConnected()) { + if (controller.get() != null) return controller.get(); + MetaTileEntity mte = GTUtility.getMetaTileEntity(getWorld(), controllerPos); + if (mte instanceof IQuantumController quantumController) { + controller = new WeakReference<>(quantumController); + return quantumController; + } else { + // controller is no longer there for some reason, need to disconnect + setDisconnected(); + tryFindNetwork(); + } + } + return null; + } + + @Override + public BlockPos getControllerPos() { + return controllerPos; + } + + @Override + public IEnergyContainer getTypeValue() { + return this.energyContainer; + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + NBTTagCompound tagCompound = super.writeToNBT(data); + tagCompound.setBoolean("HasController", controllerPos != null); + if (controllerPos != null) { + tagCompound.setLong("ControllerPos", controllerPos.toLong()); + } + return tagCompound; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + if (data.getBoolean("HasController")) { + this.controllerPos = BlockPos.fromLong(data.getLong("ControllerPos")); + } + } } diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeChest.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeChest.java index e34f104d679..3829ae30586 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeChest.java +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeChest.java @@ -33,6 +33,7 @@ import codechicken.lib.render.pipeline.IVertexOperation; import codechicken.lib.vec.Matrix4; import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -42,26 +43,13 @@ public class MetaTileEntityCreativeChest extends MetaTileEntityQuantumChest { private int itemsPerCycle = 1; private int ticksPerCycle = 1; - private final GTItemStackHandler handler = new GTItemStackHandler(this, 1) { - - @Override - protected int getStackLimit(int slot, ItemStack stack) { - return 1; - } - - @Override - public void setStackInSlot(int slot, ItemStack stack) { - this.validateSlotIndex(slot); - stack.setCount(1); - this.stacks.set(slot, stack); - this.onContentsChanged(slot); - } - }; + private final GTItemStackHandler handler; private boolean active; public MetaTileEntityCreativeChest(ResourceLocation metaTileEntityId) { super(metaTileEntityId, GTValues.MAX, 0); + this.handler = new CreativeItemStackHandler(1); } @Override @@ -72,7 +60,10 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, this); Textures.CREATIVE_CONTAINER_OVERLAY.renderSided(EnumFacing.UP, renderState, translation, pipeline); Textures.PIPE_OUT_OVERLAY.renderSided(this.getOutputFacing(), renderState, translation, pipeline); - Textures.ITEM_OUTPUT_OVERLAY.renderSided(this.getOutputFacing(), renderState, translation, pipeline); + if (!isConnected() && active) { + Textures.ITEM_OUTPUT_OVERLAY.renderSided(this.getOutputFacing(), renderState, translation, pipeline); + } + renderIndicatorOverlay(renderState, translation, pipeline); } @Override @@ -110,8 +101,14 @@ protected ModularUI createUI(EntityPlayer entityPlayer) { }).setMaxLength(11).setNumbersOnly(1, Integer.MAX_VALUE)); builder.label(7, 65, "gregtech.creative.chest.tpc"); - builder.widget(new CycleButtonWidget(7, 101, 162, 20, () -> active, value -> active = value, - "gregtech.creative.activity.off", "gregtech.creative.activity.on")); + builder.widget(new CycleButtonWidget(7, 101, 162, 20, () -> active, value -> { + active = value; + scheduleRenderUpdate(); + var c = getQuantumController(); + if (c != null) c.updateHandler(); + }, "gregtech.creative.activity.off", "gregtech.creative.activity.on")); + + builder.widget(createConnectedGui(6)); return builder.build(getHolder(), entityPlayer); } @@ -122,7 +119,7 @@ public void update() { this.virtualItemStack = stack; // For rendering purposes super.update(); if (ticksPerCycle == 0 || getOffsetTimer() % ticksPerCycle != 0) return; - if (getWorld().isRemote || !active || stack.isEmpty()) return; + if (getWorld().isRemote || !active || stack.isEmpty() || isConnected()) return; TileEntity tile = getNeighbor(getOutputFacing()); if (tile != null) { @@ -189,8 +186,44 @@ public void addInformation(ItemStack stack, @Nullable World player, List } @Override - public void receiveInitialSyncData(PacketBuffer buf) { + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { super.receiveInitialSyncData(buf); this.handler.setStackInSlot(0, this.virtualItemStack); } + + @Override + public IItemHandler getTypeValue() { + return this.handler; + } + + protected class CreativeItemStackHandler extends GTItemStackHandler { + + CreativeItemStackHandler(int size) { + super(MetaTileEntityCreativeChest.this, size); + } + + @NotNull + @Override + public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) { + return stack; + } + + @NotNull + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (!active) return ItemStack.EMPTY; + return GTUtility.copy(Math.min(amount, itemsPerCycle), getStackInSlot(0)); + } + + @Override + protected int getStackLimit(int slot, ItemStack stack) { + return 1; + } + + @Override + public void setStackInSlot(int slot, ItemStack stack) { + super.setStackInSlot(slot, stack); + virtualItemStack = GTUtility.copy(1, stack); + } + } } diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeEnergy.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeEnergy.java index 8082a778972..33e9469453d 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeEnergy.java +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeEnergy.java @@ -157,6 +157,7 @@ public void setActive(boolean active) { this.active = active; if (!getWorld().isRemote) { writeCustomData(GregtechDataCodes.UPDATE_ACTIVE, buf -> buf.writeBoolean(active)); + markDirty(); } } diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeTank.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeTank.java index 3e93c1bcbd5..fd2cb5e24e5 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeTank.java +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCreativeTank.java @@ -25,7 +25,9 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.FluidTankPropertiesWrapper; import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidTankProperties; import codechicken.lib.render.CCRenderState; import codechicken.lib.render.pipeline.ColourMultiplier; @@ -44,7 +46,7 @@ public class MetaTileEntityCreativeTank extends MetaTileEntityQuantumTank { public MetaTileEntityCreativeTank(ResourceLocation metaTileEntityId) { super(metaTileEntityId, GTValues.MAX, -1); - this.fluidTank = new FluidTank(1); + this.fluidTank = new CreativeFluidTank(1); } @Override @@ -56,12 +58,13 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, Textures.CREATIVE_CONTAINER_OVERLAY.renderSided(EnumFacing.UP, renderState, translation, pipeline); if (this.getOutputFacing() != null) { Textures.PIPE_OUT_OVERLAY.renderSided(this.getOutputFacing(), renderState, translation, pipeline); - if (isAutoOutputFluids()) { + if (!isConnected() && active) { Textures.FLUID_OUTPUT_OVERLAY.renderSided(this.getOutputFacing(), renderState, translation, pipeline); } } QuantumStorageRenderer.renderTankFluid(renderState, translation, pipeline, this.fluidTank, getWorld(), getPos(), getFrontFacing()); + renderIndicatorOverlay(renderState, translation, pipeline); } @Override @@ -100,8 +103,14 @@ protected ModularUI createUI(EntityPlayer entityPlayer) { }).setMaxLength(11).setNumbersOnly(1, Integer.MAX_VALUE)); builder.label(7, 65, "gregtech.creative.tank.tpc"); - builder.widget(new CycleButtonWidget(7, 101, 162, 20, () -> active, value -> active = value, - "gregtech.creative.activity.off", "gregtech.creative.activity.on")); + builder.widget(new CycleButtonWidget(7, 101, 162, 20, () -> active, value -> { + active = value; + scheduleRenderUpdate(); + var c = getQuantumController(); + if (c != null) c.updateHandler(); + }, "gregtech.creative.activity.off", "gregtech.creative.activity.on")); + + builder.widget(createConnectedGui(6)); return builder.build(getHolder(), entityPlayer); } @@ -110,7 +119,7 @@ protected ModularUI createUI(EntityPlayer entityPlayer) { public void update() { super.update(); if (ticksPerCycle == 0 || getOffsetTimer() % ticksPerCycle != 0 || fluidTank.getFluid() == null || - getWorld().isRemote || !active) + getWorld().isRemote || !active || isConnected()) return; TileEntity tile = getNeighbor(getOutputFacing()); @@ -121,7 +130,6 @@ public void update() { return; FluidStack stack = fluidTank.getFluid().copy(); - stack.amount = mBPerCycle; int canInsertAmount = fluidHandler.fill(stack, false); stack.amount = Math.min(mBPerCycle, canInsertAmount); @@ -165,4 +173,63 @@ public void addInformation(ItemStack stack, @Nullable World player, List I18n.format("gregtech.creative_tooltip.2") + I18n.format("gregtech.creative_tooltip.3")); // do not append the normal tooltips } + + private class CreativeFluidTank extends FluidTank { + + public CreativeFluidTank(int capacity) { + super(capacity); + } + + @Override + public IFluidTankProperties[] getTankProperties() { + if (this.tankProperties == null) { + this.tankProperties = new IFluidTankProperties[] { + new FluidTankPropertiesWrapper(fluidTank) { + + @Override + public int getCapacity() { + return mBPerCycle; + } + + @Override + public FluidStack getContents() { + if (!active) return null; + var f = super.getContents(); + if (f != null) f.amount = mBPerCycle; + return f; + } + + @Override + public boolean canDrainFluidType(FluidStack fluidStack) { + if (!active) return false; + return super.canDrainFluidType(fluidStack); + } + } + }; + } + return this.tankProperties; + } + + @Override + public FluidStack drain(FluidStack resource, boolean doDrain) { + return drain(resource == null ? 0 : resource.amount, doDrain); + } + + @Override + public FluidStack drain(int maxDrain, boolean doDrain) { + if (!active) return null; + + var f = super.drain(maxDrain, false); + if (f != null) { + f = f.copy(); + f.amount = Math.min(mBPerCycle, maxDrain); + } + return f; + } + + @Override + public int fill(FluidStack resource, boolean doFill) { + return 0; + } + } } diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumChest.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumChest.java index f51405428e6..d6646cb40de 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumChest.java +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumChest.java @@ -61,7 +61,7 @@ import static gregtech.api.capability.GregtechDataCodes.*; -public class MetaTileEntityQuantumChest extends MetaTileEntity +public class MetaTileEntityQuantumChest extends MetaTileEntityQuantumStorage implements ITieredMetaTileEntity, IActiveOutputSide, IFastRenderMetaTileEntity { private final int tier; @@ -111,6 +111,7 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, Textures.ITEM_OUTPUT_OVERLAY.renderSided(outputFacing, renderState, translation, pipeline); } } + renderIndicatorOverlay(renderState, translation, pipeline); } @Override @@ -159,7 +160,10 @@ public void update() { } if (previousStack == null || !areItemStackIdentical(previousStack, virtualItemStack)) { - writeCustomData(UPDATE_ITEM, buf -> buf.writeItemStack(virtualItemStack)); + writeCustomData(UPDATE_ITEM, buf -> { + virtualItemStack.setCount(1); + buf.writeItemStack(virtualItemStack); + }); previousStack = virtualItemStack; } if (previousStackSize != itemsStoredInside) { @@ -187,7 +191,6 @@ protected void addDisplayInformation(List textList) { @Override public void addInformation(ItemStack stack, @Nullable World player, List tooltip, boolean advanced) { super.addInformation(stack, player, tooltip, advanced); - tooltip.add(I18n.format("gregtech.machine.quantum_chest.tooltip")); tooltip.add(I18n.format("gregtech.universal.tooltip.item_storage_total", maxStoredItems)); NBTTagCompound compound = stack.getTagCompound(); @@ -350,6 +353,8 @@ protected ModularUI createUI(EntityPlayer entityPlayer) { .shouldUseBaseBackground()) .bindPlayerInventory(entityPlayer.inventory); + builder.widget(createConnectedGui(64)); + return builder.build(getHolder(), entityPlayer); } @@ -382,17 +387,18 @@ public boolean onWrenchClick(EntityPlayer playerIn, EnumHand hand, EnumFacing fa } @Override - public void writeInitialSyncData(PacketBuffer buf) { + public void writeInitialSyncData(@NotNull PacketBuffer buf) { super.writeInitialSyncData(buf); buf.writeByte(getOutputFacing().getIndex()); buf.writeBoolean(autoOutputItems); + this.virtualItemStack.setCount(1); buf.writeItemStack(virtualItemStack); buf.writeLong(itemsStoredInside); buf.writeBoolean(voiding); } @Override - public void receiveInitialSyncData(PacketBuffer buf) { + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { super.receiveInitialSyncData(buf); this.outputFacing = EnumFacing.VALUES[buf.readByte()]; this.autoOutputItems = buf.readBoolean(); @@ -414,7 +420,7 @@ public boolean isValidFrontFacing(EnumFacing facing) { } @Override - public void receiveCustomData(int dataId, PacketBuffer buf) { + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { super.receiveCustomData(dataId, buf); if (dataId == UPDATE_OUTPUT_FACING) { this.outputFacing = EnumFacing.VALUES[buf.readByte()]; @@ -548,6 +554,16 @@ public void setAllowInputFromOutputSide(boolean allowInputFromOutputSide) { } } + @Override + public Type getType() { + return Type.ITEM; + } + + @Override + public IItemHandler getTypeValue() { + return this.combinedInventory; + } + @Override public AxisAlignedBB getRenderBoundingBox() { return new AxisAlignedBB(getPos()); diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumExtender.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumExtender.java new file mode 100644 index 00000000000..cc37c7385ca --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumExtender.java @@ -0,0 +1,81 @@ +package gregtech.common.metatileentities.storage; + +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.capability.IDualHandler; +import gregtech.api.gui.ModularUI; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; +import gregtech.api.util.GTUtility; +import gregtech.client.renderer.texture.Textures; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.ColourMultiplier; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Matrix4; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.NotNull; + +public class MetaTileEntityQuantumExtender extends MetaTileEntityQuantumStorage { + + public MetaTileEntityQuantumExtender(ResourceLocation metaTileEntityId) { + super(metaTileEntityId); + } + + @Override + public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { + return new MetaTileEntityQuantumExtender(metaTileEntityId); + } + + @Override + public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + var newPipeline = ArrayUtils.add(pipeline, + new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(getPaintingColorForRendering()))); + if (isConnected() && getQuantumController().isPowered()) { + Textures.QUANTUM_EXTENDER_ACTIVE.render(renderState, translation, newPipeline); + } else { + Textures.QUANTUM_EXTENDER.render(renderState, translation, newPipeline); + } + } + + @Override + public Pair getParticleTexture() { + return Pair.of(Textures.QUANTUM_EXTENDER.getParticleSprite(), getPaintingColorForRendering()); + } + + @Override + protected ModularUI createUI(EntityPlayer entityPlayer) { + return null; + } + + @Override + protected boolean openGUIOnRightClick() { + return false; + } + + @Override + public boolean hasFrontFacing() { + return false; + } + + @Override + public Type getType() { + return Type.EXTENDER; + } + + @Override + public IDualHandler getTypeValue() { + return null; + } + + @Override + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { + super.receiveCustomData(dataId, buf); + if (dataId == GregtechDataCodes.REMOVE_CONTROLLER) scheduleRenderUpdate(); + } +} diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumProxy.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumProxy.java new file mode 100644 index 00000000000..42deb4d91aa --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumProxy.java @@ -0,0 +1,105 @@ +package gregtech.common.metatileentities.storage; + +import gregtech.api.capability.IDualHandler; +import gregtech.api.capability.IQuantumController; +import gregtech.api.gui.ModularUI; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; +import gregtech.api.util.GTUtility; +import gregtech.client.renderer.texture.Textures; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.ColourMultiplier; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Matrix4; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; + +public class MetaTileEntityQuantumProxy extends MetaTileEntityQuantumStorage { + + public MetaTileEntityQuantumProxy(ResourceLocation metaTileEntityId) { + super(metaTileEntityId); + } + + @Override + public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { + return new MetaTileEntityQuantumProxy(metaTileEntityId); + } + + @Override + public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + var newPipeline = ArrayUtils.add(pipeline, + new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(getPaintingColorForRendering()))); + if (isConnected() && getQuantumController().isPowered()) { + Textures.QUANTUM_PROXY_ACTIVE.render(renderState, translation, newPipeline); + } else { + Textures.QUANTUM_PROXY_INACTIVE.render(renderState, translation, newPipeline); + } + } + + @Override + public Pair getParticleTexture() { + return Pair.of(Textures.QUANTUM_PROXY_INACTIVE.getParticleSprite(), getPaintingColorForRendering()); + } + + @Override + protected ModularUI createUI(EntityPlayer entityPlayer) { + return null; + } + + @Override + protected boolean openGUIOnRightClick() { + return false; + } + + @Override + public boolean hasFrontFacing() { + return false; + } + + @Override + public T getCapability(Capability capability, EnumFacing side) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || + capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { + var controller = getPoweredController(); + if (controller != null) + return controller.getCapability(capability, side); + } + return super.getCapability(capability, side); + } + + @Override + public void setDisconnected() { + super.setDisconnected(); + notifyBlockUpdate(); + } + + @Override + public Type getType() { + return Type.PROXY; + } + + @Override + public IDualHandler getTypeValue() { + var controller = getPoweredController(); + if (controller == null) return null; + return controller.getHandler(); + } + + @Nullable + private IQuantumController getPoweredController() { + if (!isConnected()) return null; + var controller = getQuantumController(); + if (controller == null || !controller.isPowered()) return null; + return controller; + } +} diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumStorage.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumStorage.java new file mode 100644 index 00000000000..d57f907af8d --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumStorage.java @@ -0,0 +1,216 @@ +package gregtech.common.metatileentities.storage; + +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.capability.IQuantumController; +import gregtech.api.capability.IQuantumStorage; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.widgets.ClickButtonWidget; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.util.GTUtility; +import gregtech.client.renderer.handler.BlockPosHighlightRenderer; +import gregtech.client.renderer.texture.Textures; +import gregtech.client.renderer.texture.cube.SimpleOverlayRenderer; +import gregtech.client.utils.RenderUtil; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Matrix4; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.util.List; + +public abstract class MetaTileEntityQuantumStorage extends MetaTileEntity implements IQuantumStorage { + + /** not synced, server only. lazily initialized from pos */ + private WeakReference controller = new WeakReference<>(null); + + /** synced, server and client */ + private BlockPos controllerPos; + + private ClickButtonWidget connectedIcon; + + public MetaTileEntityQuantumStorage(ResourceLocation metaTileEntityId) { + super(metaTileEntityId); + } + + @SuppressWarnings("DataFlowIssue") + @SideOnly(Side.CLIENT) + protected void renderIndicatorOverlay(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + SimpleOverlayRenderer texture; + if (isConnected()) { + texture = getQuantumController().isPowered() ? + Textures.QUANTUM_INDICATOR_POWERED : + Textures.QUANTUM_INDICATOR_CONNECTED; + } else { + texture = Textures.QUANTUM_INDICATOR; + } + texture.renderSided(getFrontFacing(), renderState, RenderUtil.adjustTrans(translation, getFrontFacing(), 1), + pipeline); + } + + @Override + public void setConnected(IQuantumController controller) { + if (getWorld().isRemote) return; + + if (!controller.getPos().equals(controllerPos)) { + this.controller = new WeakReference<>(controller); + this.controllerPos = controller.getPos(); + writeCustomData(GregtechDataCodes.UPDATE_CONTROLLER_POS, buf -> buf.writeBlockPos(controllerPos)); + markDirty(); + } + } + + @Override + public void setDisconnected() { + if (getWorld().isRemote) return; + + controller.clear(); + controllerPos = null; + writeCustomData(GregtechDataCodes.REMOVE_CONTROLLER, buf -> {}); + markDirty(); + } + + // use this to make sure controller is properly initialized + @Override + public final IQuantumController getQuantumController() { + if (isConnected()) { + if (controller.get() != null) return controller.get(); + MetaTileEntity mte = GTUtility.getMetaTileEntity(getWorld(), controllerPos); + if (mte instanceof IQuantumController quantumController) { + controller = new WeakReference<>(quantumController); + return quantumController; + } else { + // controller is no longer there for some reason, need to disconnect + setDisconnected(); + tryFindNetwork(); + } + } + return null; + } + + @Override + public BlockPos getControllerPos() { + return controllerPos; + } + + @Override + public void onRemoval() { + if (!getWorld().isRemote && isConnected()) { + IQuantumController controller = getQuantumController(); + if (controller != null) controller.rebuildNetwork(); + } + } + + @Override + public void onPlacement(@Nullable EntityLivingBase placer) { + super.onPlacement(placer); + if (getWorld() == null || getWorld().isRemote) + return; + + // add to the network if an adjacent block is part of a network + // use whatever we find first, merging networks is not supported + tryFindNetwork(); + } + + @Override + public void writeInitialSyncData(@NotNull PacketBuffer buf) { + super.writeInitialSyncData(buf); + buf.writeBoolean(controllerPos != null); + if (controllerPos != null) { + buf.writeBlockPos(controllerPos); + } + } + + @Override + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { + super.receiveInitialSyncData(buf); + if (buf.readBoolean()) { + controllerPos = buf.readBlockPos(); + scheduleRenderUpdate(); + } + } + + @Override + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { + super.receiveCustomData(dataId, buf); + if (dataId == GregtechDataCodes.UPDATE_CONTROLLER_POS) { + this.controllerPos = buf.readBlockPos(); + this.controller.clear(); + + if (this.connectedIcon != null) { + this.connectedIcon.setButtonTexture(GuiTextures.GREGTECH_LOGO); + this.connectedIcon.setTooltipText("gregtech.machine.quantum_storage.connected", + controllerPos.getX(), controllerPos.getZ(), controllerPos.getY()); + } + scheduleRenderUpdate(); + } else if (dataId == GregtechDataCodes.REMOVE_CONTROLLER) { + this.controllerPos = null; + this.controller.clear(); + if (this.connectedIcon != null) { + this.connectedIcon.setButtonTexture(GuiTextures.GREGTECH_LOGO_DARK); + this.connectedIcon.setTooltipText("gregtech.machine.quantum_storage.disconnected"); + } + scheduleRenderUpdate(); + } else if (dataId == GregtechDataCodes.LOCATE_CONTROLLER) { + // tell controller to highlight + BlockPosHighlightRenderer.renderBlockBoxHighLight(getControllerPos(), 6000, 1500); + Minecraft.getMinecraft().player.closeScreen(); + } + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + NBTTagCompound tagCompound = super.writeToNBT(data); + tagCompound.setBoolean("HasController", controllerPos != null); + if (controllerPos != null) { + tagCompound.setLong("ControllerPos", controllerPos.toLong()); + } + return tagCompound; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + if (data.getBoolean("HasController")) { + this.controllerPos = BlockPos.fromLong(data.getLong("ControllerPos")); + } + } + + protected ClickButtonWidget createConnectedGui(int y) { + connectedIcon = new ClickButtonWidget(151, y, 18, 18, "", + clickData -> { + if (isConnected()) + writeCustomData(GregtechDataCodes.LOCATE_CONTROLLER, buffer -> {}); + }); + connectedIcon.setButtonTexture(isConnected() ? GuiTextures.GREGTECH_LOGO : GuiTextures.GREGTECH_LOGO_DARK); + + if (isConnected()) { + connectedIcon.setTooltipText("gregtech.machine.quantum_storage.connected", + controllerPos.getX(), controllerPos.getZ(), controllerPos.getY()); + } else { + connectedIcon.setTooltipText("gregtech.machine.quantum_storage.disconnected"); + } + + return connectedIcon; + } + + @Override + public void addInformation(ItemStack stack, @Nullable World world, @NotNull List tooltip, + boolean advanced) { + tooltip.add(I18n.format("gregtech.machine.quantum_chest.tooltip")); + } +} diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumStorageController.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumStorageController.java new file mode 100644 index 00000000000..c4431e902a9 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumStorageController.java @@ -0,0 +1,519 @@ +package gregtech.common.metatileentities.storage; + +import gregtech.api.GTValues; +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.capability.IDualHandler; +import gregtech.api.capability.IEnergyContainer; +import gregtech.api.capability.IQuantumController; +import gregtech.api.capability.IQuantumStorage; +import gregtech.api.capability.impl.EnergyContainerList; +import gregtech.api.capability.impl.FluidTankList; +import gregtech.api.capability.impl.ItemHandlerList; +import gregtech.api.metatileentity.ITieredMetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; +import gregtech.api.util.GTUtility; +import gregtech.client.renderer.texture.Textures; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagLong; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.IFluidTank; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.ColourMultiplier; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Matrix4; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +import static gregtech.api.capability.IQuantumStorage.Type.*; + +public class MetaTileEntityQuantumStorageController extends MetaTileEntity implements IQuantumController { + + private static final int MAX_DISTANCE_RADIUS = 16; + + private EnergyContainerList energyHandler = new EnergyContainerList(Collections.emptyList()); + private final List energyContainers = new ArrayList<>(); + /** Somewhat lazily initialized, make sure to call {@code getStorage()} before trying to access anything in this */ + private Map>> storageInstances = new HashMap<>(); + + /** The "definitive" set of positions of storage instances */ + private Set storagePositions = new HashSet<>(); + private final Map> typePosMap = new EnumMap<>(IQuantumStorage.Type.class); + private final BlockPos[] bounds = new BlockPos[2]; + private long energyConsumption = 0; + private final QuantumControllerHandler handler = new QuantumControllerHandler(); + + private boolean isDead = false; + private boolean isPowered = false; + + public MetaTileEntityQuantumStorageController(ResourceLocation metaTileEntityId) { + super(metaTileEntityId); + for (var type : VALUES) { + typePosMap.put(type, new HashSet<>()); + } + } + + @Override + public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { + return new MetaTileEntityQuantumStorageController(metaTileEntityId); + } + + @Override + public void update() { + super.update(); + if (getWorld().isRemote) return; + + if (getOffsetTimer() % 10 == 0) { + boolean isPowered = energyHandler.getEnergyStored() > energyConsumption && energyConsumption > 0; + if (isPowered) energyHandler.removeEnergy(energyConsumption); + + if (isPowered != this.isPowered) { + this.isPowered = isPowered; + + writeCustomData(GregtechDataCodes.UPDATE_ENERGY, buf -> { + buf.writeBoolean(this.isPowered); + buf.writeBlockPos(this.bounds[0]); + buf.writeBlockPos(this.bounds[1]); + }); + updateHandler(); + } + } + } + + public boolean isPowered() { + return isPowered; + } + + @Override + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { + super.receiveCustomData(dataId, buf); + if (dataId == GregtechDataCodes.UPDATE_ENERGY) { + this.isPowered = buf.readBoolean(); + getWorld().markBlockRangeForRenderUpdate(buf.readBlockPos(), buf.readBlockPos()); + scheduleRenderUpdate(); + } else if (dataId == GregtechDataCodes.UPDATE_ENERGY_PER) { + this.energyConsumption = buf.readLong(); + } + } + + @Override + public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + var front = isPowered() ? + Textures.QUANTUM_CONTROLLER_FRONT_ACTIVE : + Textures.QUANTUM_CONTROLLER_FRONT_INACTIVE; + var sides = isPowered() ? + Textures.QUANTUM_CONTROLLER_ACTIVE : + Textures.QUANTUM_CONTROLLER_INACTIVE; + + var newPipeline = ArrayUtils.add(pipeline, + new ColourMultiplier(GTUtility.convertRGBtoOpaqueRGBA_CL(getPaintingColorForRendering()))); + + front.renderSided(getFrontFacing(), renderState, translation, newPipeline); + + for (EnumFacing facing : EnumFacing.VALUES) { + if (facing == getFrontFacing()) continue; + sides.renderSided(facing, renderState, translation, newPipeline); + } + } + + @Override + public Pair getParticleTexture() { + return Pair.of(Textures.QUANTUM_CONTROLLER_ACTIVE.getParticleSprite(), getPaintingColorForRendering()); + } + + @Override + protected boolean openGUIOnRightClick() { + return false; // todo use mui2 for ui? + } + + @Override + public boolean isValidFrontFacing(EnumFacing facing) { + return true; + } + + @Nullable + @SuppressWarnings("SameParameterValue") + private IQuantumStorage getStorage(BlockPos pos, boolean rebuild) { + if (getWorld().isRemote) return null; + if (storageInstances.containsKey(pos)) { + WeakReference> storageRef = storageInstances.get(pos); + IQuantumStorage storage = storageRef.get(); + if (storage != null) { + return storage; + } + } + // need to make sure it still exists + MetaTileEntity mte = GTUtility.getMetaTileEntity(getWorld(), pos); + if (mte instanceof IQuantumStoragestorage) { + storageInstances.put(pos, new WeakReference<>(storage)); + return storage; + } else if (rebuild) { + // need to remove and rebuild + storagePositions.remove(pos); + rebuildNetwork(); + return null; + } + return null; + } + + @Nullable + public final IQuantumStorage getStorage(BlockPos pos) { + return getStorage(pos, false); + } + + @Override + public boolean canConnect(IQuantumStorage storage) { + return !isDead && isInRange(storage.getPos()); + } + + private boolean isInRange(BlockPos pos) { + return Math.abs(getPos().getX() - pos.getX()) <= MAX_DISTANCE_RADIUS && // valid X + Math.abs(getPos().getY() - pos.getY()) <= MAX_DISTANCE_RADIUS && // valid Y + Math.abs(getPos().getZ() - pos.getZ()) <= MAX_DISTANCE_RADIUS; // valid Z + } + + @Override + public void onRemoval() { + if (getWorld().isRemote) return; + isDead = true; + for (BlockPos pos : storagePositions) { + IQuantumStorage storage = getStorage(pos); + if (storage != null) storage.setDisconnected(); + } + handler.invalidate(); + storagePositions.clear(); + storageInstances.clear(); + typePosMap.clear(); + } + + @Override + public void onPlacement(@Nullable EntityLivingBase placer) { + super.onPlacement(placer); + rebuildNetwork(); + } + + @Override + public void onLoad() { + calculateEnergyUsage(); + super.onLoad(); + } + + // Used when this controller is initially placed. Try to find all possible + // storage instances that are connected and within our distance radius + @Override + public void rebuildNetwork() { + if (getWorld().isRemote) return; + var oldInstances = storageInstances; + var oldPositions = storagePositions; + + storageInstances = new HashMap<>(); + storagePositions = new HashSet<>(); + + typePosMap.values().forEach(Set::clear); + + Queue searchQueue = new ArrayDeque<>(); + Set checked = new HashSet<>(); + + // check the posses around the controller + for (EnumFacing facing : EnumFacing.VALUES) { + if (checkStorageNeighbor(this, facing)) { + searchQueue.add(getPos().offset(facing)); + } + } + + int minx = getPos().getX(); + int miny = getPos().getY(); + int minz = getPos().getZ(); + int maxx = minx; + int maxy = miny; + int maxz = minz; + + // while there are blocks to search + while (!searchQueue.isEmpty()) { + BlockPos pos = searchQueue.remove(); + + if (!checked.add(pos)) + continue; + + if (!isInRange(pos) || !getWorld().isBlockLoaded(pos, false)) continue; + + var state = getWorld().getBlockState(pos); + if (state.getBlock().isAir(state, getWorld(), pos)) continue; + + MetaTileEntity mte = GTUtility.getMetaTileEntity(getWorld(), pos); + // the mte at this pos is always an instance of quantum storage + IQuantumStorage storage = (IQuantumStorage) mte; + + // connected to some other network already, ignore + if (storage.isConnected() && !storage.getControllerPos().equals(getPos())) continue; + + // valid chest/tank located, add it + storageInstances.put(pos, new WeakReference<>(storage)); + storagePositions.add(pos); + typePosMap.get(storage.getType()).add(pos); + storage.setConnected(this); + oldInstances.remove(pos); + oldPositions.remove(pos); + + // calculate bounds + minx = Math.min(minx, pos.getX()); + miny = Math.min(miny, pos.getY()); + minz = Math.min(minz, pos.getZ()); + + maxx = Math.max(maxx, pos.getX()); + maxy = Math.max(maxy, pos.getY()); + maxz = Math.max(maxz, pos.getZ()); + + // check against already check posses so we don't recheck a checked pos + for (EnumFacing facing : EnumFacing.VALUES) { + BlockPos offsetPos = pos.offset(facing); + if (checked.contains(offsetPos) || getPos().equals(offsetPos)) continue; + state = getWorld().getBlockState(offsetPos); + if (state.getBlock().isAir(state, getWorld(), offsetPos)) continue; + + // add a new pos to search + if (checkStorageNeighbor(mte, facing)) + searchQueue.add(offsetPos); + } + } + + // update bounds + this.bounds[0] = new BlockPos(minx, miny, minz); + this.bounds[1] = new BlockPos(maxx, maxy, maxz); + + // check old posses to disconnect the storages + for (BlockPos pos : oldPositions) { + + // if we already checked this pos before, don't check it again + if (checked.contains(pos)) continue; + + // if the pos is air, there's nothing to check + var state = getWorld().getBlockState(pos); + if (state.getBlock().isAir(state, getWorld(), pos)) continue; + + IQuantumStorage storage = oldInstances.get(pos).get(); + if (storage == null) { + MetaTileEntity mte = GTUtility.getMetaTileEntity(getWorld(), pos); + if (!(mte instanceof IQuantumStoragequantumStorage)) { + continue; + } + storage = quantumStorage; + } + storage.setDisconnected(); + } + handler.rebuildCache(); + calculateEnergyUsage(); + markDirty(); + } + + private static boolean checkStorageNeighbor(MetaTileEntity mte, EnumFacing facing) { + if (mte.getNeighbor(facing) instanceof IGregTechTileEntity gtte) { + return gtte.getMetaTileEntity() instanceof IQuantumStorage; + } + return false; + } + + @Override + public void updateHandler() { + if (getWorld().isRemote) return; + notifyBlockUpdate(); + for (var pos : typePosMap.get(PROXY)) { + var storage = getStorage(pos); + if (storage == null) continue; + storage.notifyBlockUpdate(); + } + } + + private void calculateEnergyUsage() { + energyContainers.clear(); + energyConsumption = 0; + for (var pos : storagePositions) { + var storage = getStorage(pos); + if (storage != null) { + typePosMap.get(storage.getType()).add(pos); + energyConsumption += getTypeEnergy(storage); + if (storage.getType() == ENERGY) { + energyContainers.add((IEnergyContainer) storage.getTypeValue()); + } + } + } + energyHandler = new EnergyContainerList(energyContainers); + writeCustomData(GregtechDataCodes.UPDATE_ENERGY_PER, buf -> buf.writeLong(energyConsumption)); + } + + public long getTypeEnergy(IQuantumStorage storage) { + return switch (storage.getType()) { + case ITEM, FLUID -> { + int tier = storage instanceof ITieredMetaTileEntity tieredMTE ? tieredMTE.getTier() : 1; + yield tier > 5 ? + GTValues.VH[GTValues.HV] : + GTValues.VH[GTValues.LV]; + } + case PROXY -> 8L; + case EXTENDER -> 2L; + case ENERGY -> 1L; + }; + } + + @Override + public int getCount(IQuantumStorage.Type type) { + return typePosMap.get(type).size(); + } + + public final long getEnergyUsage() { + return energyConsumption; + } + + @Override + public void writeInitialSyncData(@NotNull PacketBuffer buf) { + super.writeInitialSyncData(buf); + buf.writeBoolean(this.isPowered); + buf.writeLong(this.energyConsumption); + } + + @Override + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { + super.receiveInitialSyncData(buf); + this.isPowered = buf.readBoolean(); + this.energyConsumption = buf.readLong(); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + NBTTagCompound tagCompound = super.writeToNBT(data); + NBTTagList list = new NBTTagList(); + for (BlockPos pos : storagePositions) { + list.appendTag(new NBTTagLong(pos.toLong())); + } + tagCompound.setTag("StorageInstances", list); + tagCompound.setLong("MinBound", bounds[0].toLong()); + tagCompound.setLong("MaxBound", bounds[1].toLong()); + tagCompound.setBoolean("isPowered", this.isPowered); + return tagCompound; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + NBTTagList list = data.getTagList("StorageInstances", Constants.NBT.TAG_LONG); + for (int i = 0; i < list.tagCount(); i++) { + storagePositions.add(BlockPos.fromLong(((NBTTagLong) list.get(i)).getLong())); + } + this.bounds[0] = BlockPos.fromLong(data.getLong("MinBound")); + this.bounds[1] = BlockPos.fromLong(data.getLong("MaxBound")); + this.isPowered = data.getBoolean("isPowered"); + } + + @SuppressWarnings("unchecked") + @Override + public T getCapability(@NotNull Capability capability, EnumFacing side) { + if (isPowered()) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY && handler.hasItemHandlers()) { + return (T) handler.getItemHandlers(); + } else if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && handler.hasFluidTanks()) { + return (T) handler.getFluidTanks(); + } + } + + return super.getCapability(capability, side); + } + + @Override + public void addInformation(ItemStack stack, @Nullable World world, @NotNull List tooltip, + boolean advanced) { + tooltip.add(I18n.format("gregtech.machine.quantum_chest.tooltip")); + } + + @Override + public IDualHandler getHandler() { + return this.handler; + } + + // todo use DualHandler instead once the multis ability pr is merged + private class QuantumControllerHandler implements IDualHandler { + + // IFluidHandler saved values + private FluidTankList fluidTanks; + + // IItemHandler saved values + private ItemHandlerList itemHandlers; + + private void invalidate() { + fluidTanks = new FluidTankList(false); + itemHandlers = new ItemHandlerList(Collections.emptyList()); + } + + private void rebuildCache() { + List itemHandlerList = new ArrayList<>(); + List fluidTankList = new ArrayList<>(); + for (BlockPos pos : storagePositions) { + IQuantumStorage storage = getStorage(pos); + if (storage == null) continue; + switch (storage.getType()) { + case ITEM -> itemHandlerList.add((IItemHandler) storage.getTypeValue()); + case FLUID -> fluidTankList.add((IFluidTank) storage.getTypeValue()); + } + } + + // todo allow this "allowSameFluidFill" to be configured in this controller? + this.fluidTanks = new FluidTankList(false, fluidTankList); + this.itemHandlers = new ItemHandlerList(itemHandlerList); + } + + @Override + public boolean hasFluidTanks() { + return getFluidTanks().getTanks() > 0; + } + + @Override + public boolean hasItemHandlers() { + return !getItemHandlers().getBackingHandlers().isEmpty(); + } + + @Override + public FluidTankList getFluidTanks() { + if (fluidTanks == null) { + rebuildCache(); + } + return fluidTanks; + } + + @Override + public ItemHandlerList getItemHandlers() { + if (itemHandlers == null) { + rebuildCache(); + } + return itemHandlers; + } + } +} diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java index 41db93d301b..0d675b9b1c9 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityQuantumTank.java @@ -50,6 +50,7 @@ import net.minecraftforge.common.util.Constants; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.fluids.IFluidTank; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fml.relauncher.Side; @@ -73,7 +74,7 @@ import static gregtech.api.capability.GregtechDataCodes.*; import static net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack.FLUID_NBT_KEY; -public class MetaTileEntityQuantumTank extends MetaTileEntity +public class MetaTileEntityQuantumTank extends MetaTileEntityQuantumStorage implements ITieredMetaTileEntity, IActiveOutputSide, IFastRenderMetaTileEntity { private final int tier; @@ -287,6 +288,7 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, } QuantumStorageRenderer.renderTankFluid(renderState, translation, pipeline, fluidTank, getWorld(), getPos(), getFrontFacing()); + renderIndicatorOverlay(renderState, translation, pipeline); } @Override @@ -305,7 +307,6 @@ public Pair getParticleTexture() { @Override public void addInformation(ItemStack stack, @Nullable World player, List tooltip, boolean advanced) { - super.addInformation(stack, player, tooltip, advanced); tooltip.add(I18n.format("gregtech.machine.quantum_tank.tooltip")); tooltip.add(I18n.format("gregtech.universal.tooltip.fluid_storage_capacity", maxFluidCapacity)); NBTTagCompound tag = stack.getTagCompound(); @@ -349,8 +350,8 @@ protected ModularUI createUI(EntityPlayer entityPlayer) { }) .setAlwaysShowFull(true).setDrawHoveringText(false); - return ModularUI.defaultBuilder() - .widget(new ImageWidget(7, 16, 81, 46, GuiTextures.DISPLAY)) + ModularUI.Builder builder = ModularUI.defaultBuilder(); + builder.widget(new ImageWidget(7, 16, 81, 46, GuiTextures.DISPLAY)) .widget(new LabelWidget(11, 20, "gregtech.gui.fluid_amount", 0xFFFFFF)) .widget(tankWidget) .widget(new AdvancedTextWidget(11, 30, getFluidAmountText(tankWidget), 0xFFFFFF)) @@ -371,8 +372,11 @@ protected ModularUI createUI(EntityPlayer entityPlayer) { .widget(new ToggleButtonWidget(43, 64, 18, 18, GuiTextures.BUTTON_FLUID_VOID, this::isVoiding, this::setVoiding) .setTooltipText("gregtech.gui.fluid_voiding.tooltip") - .shouldUseBaseBackground()) - .bindPlayerInventory(entityPlayer.inventory) + .shouldUseBaseBackground()); + + builder.widget(createConnectedGui(64)); + + return builder.bindPlayerInventory(entityPlayer.inventory) .build(getHolder(), entityPlayer); } @@ -451,7 +455,7 @@ public boolean isAllowInputFromOutputSideFluids() { } @Override - public void receiveCustomData(int dataId, PacketBuffer buf) { + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { super.receiveCustomData(dataId, buf); if (dataId == UPDATE_OUTPUT_FACING) { this.outputFacing = EnumFacing.VALUES[buf.readByte()]; @@ -488,7 +492,7 @@ public boolean isValidFrontFacing(EnumFacing facing) { } @Override - public void writeInitialSyncData(PacketBuffer buf) { + public void writeInitialSyncData(@NotNull PacketBuffer buf) { super.writeInitialSyncData(buf); buf.writeByte(getOutputFacing().getIndex()); buf.writeBoolean(autoOutputFluids); @@ -499,7 +503,7 @@ public void writeInitialSyncData(PacketBuffer buf) { } @Override - public void receiveInitialSyncData(PacketBuffer buf) { + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { super.receiveInitialSyncData(buf); this.outputFacing = EnumFacing.VALUES[buf.readByte()]; @@ -714,4 +718,14 @@ public int getPriority() { return !locked || lockedFluid == null ? IFilter.noPriority() : IFilter.whitelistPriority(1); } } + + @Override + public Type getType() { + return Type.FLUID; + } + + @Override + public IFluidTank getTypeValue() { + return fluidTank; + } } diff --git a/src/main/java/gregtech/integration/theoneprobe/TheOneProbeModule.java b/src/main/java/gregtech/integration/theoneprobe/TheOneProbeModule.java index 6be618fabb6..4ce285fc92e 100644 --- a/src/main/java/gregtech/integration/theoneprobe/TheOneProbeModule.java +++ b/src/main/java/gregtech/integration/theoneprobe/TheOneProbeModule.java @@ -43,6 +43,7 @@ public void init(FMLInitializationEvent event) { oneProbe.registerProvider(new LampInfoProvider()); oneProbe.registerProvider(new LDPipeProvider()); oneProbe.registerProvider(new LaserContainerInfoProvider()); + oneProbe.registerProvider(new QuantumStorageProvider()); oneProbe.registerProvider(new ActiveTransformerInfoProvider()); oneProbe.registerProvider(new BatteryBufferInfoProvider()); diff --git a/src/main/java/gregtech/integration/theoneprobe/provider/QuantumStorageProvider.java b/src/main/java/gregtech/integration/theoneprobe/provider/QuantumStorageProvider.java new file mode 100644 index 00000000000..792be0ac4e5 --- /dev/null +++ b/src/main/java/gregtech/integration/theoneprobe/provider/QuantumStorageProvider.java @@ -0,0 +1,68 @@ +package gregtech.integration.theoneprobe.provider; + +import gregtech.api.GTValues; +import gregtech.api.capability.IQuantumController; +import gregtech.api.capability.IQuantumStorage; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; +import gregtech.api.util.GTUtility; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; + +import mcjty.theoneprobe.api.IProbeHitData; +import mcjty.theoneprobe.api.IProbeInfo; +import mcjty.theoneprobe.api.IProbeInfoProvider; +import mcjty.theoneprobe.api.ProbeMode; +import mcjty.theoneprobe.api.TextStyleClass; +import org.jetbrains.annotations.NotNull; + +public class QuantumStorageProvider implements IProbeInfoProvider { + + @Override + public String getID() { + return ":quantum_storage_provider"; + } + + @Override + public void addProbeInfo(ProbeMode mode, IProbeInfo probeInfo, EntityPlayer player, World world, + IBlockState blockState, IProbeHitData data) { + if (blockState.getBlock().hasTileEntity(blockState) && + world.getTileEntity(data.getPos()) instanceof IGregTechTileEntity gtte) { + if (gtte.getMetaTileEntity() instanceof IQuantumController controller) { + if (controller.getCount(IQuantumStorage.Type.ENERGY) == 0) { + probeInfo.text("{*gregtech.top.quantum_controller.no_hatches*}"); + } else if (!controller.isPowered()) { + probeInfo.text("{*gregtech.top.quantum_controller.no_power*}"); + } else { + long usage = controller.getEnergyUsage(); + configureEnergyUsage(usage / 10, probeInfo); + } + } else if (gtte.getMetaTileEntity() instanceof IQuantumStoragestorage && + (storage.getType() == IQuantumStorage.Type.ITEM || + storage.getType() == IQuantumStorage.Type.FLUID)) { + probeInfo.text(getConnectionStatus(storage)); + } + } + } + + private static @NotNull String getConnectionStatus(IQuantumStorage storage) { + var qcontroller = storage.getQuantumController(); + String status = "gregtech.top.quantum_status.disconnected"; + if (qcontroller != null) { + status = qcontroller.isPowered() ? + "gregtech.top.quantum_status.powered" : + "gregtech.top.quantum_status.connected"; + } + return TextStyleClass.INFO + "{*gregtech.top.quantum_status.label*} " + + "{*" + status + "*}"; + } + + public void configureEnergyUsage(long EUs, IProbeInfo probeInfo) { + if (EUs == 0) return; + String text = TextFormatting.RED.toString() + EUs + TextStyleClass.INFO + " EU/t" + TextFormatting.GREEN + + " (" + GTValues.VNF[GTUtility.getTierByVoltage(EUs)] + TextFormatting.GREEN + ")"; + probeInfo.text(TextStyleClass.INFO + "{*gregtech.top.energy_consumption*} " + text); + } +} diff --git a/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java b/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java index 192c35d1d16..840fd0077d8 100644 --- a/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java +++ b/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java @@ -1001,6 +1001,35 @@ public static void init() { "PPP", "PFP", "PPP", 'P', new UnificationEntry(OrePrefix.plate, Materials.Neutronium), 'F', new UnificationEntry(OrePrefix.pipeLargeFluid, Materials.Duranium)); + // Quantum Storage Controller + ModHandler.addShapedRecipe(true, "quantum_storage_controller", + MetaTileEntities.QUANTUM_STORAGE_CONTROLLER.getStackForm(), + "PCP", "EHS", "CFC", + 'C', new UnificationEntry(OrePrefix.circuit, Tier.MV), + 'P', new UnificationEntry(OrePrefix.plate, Materials.Steel), + 'H', MetaTileEntities.HULL[GTValues.MV].getStackForm(), + 'F', MetaItems.FIELD_GENERATOR_MV.getStackForm(), + 'E', MetaItems.EMITTER_MV.getStackForm(), + 'S', MetaItems.SENSOR_MV.getStackForm()); + + // Quantum Storage Proxy + ModHandler.addShapedRecipe(true, "quantum_storage_proxy", + MetaTileEntities.QUANTUM_STORAGE_PROXY.getStackForm(), + "PEP", "ACA", "PHP", + 'P', new UnificationEntry(OrePrefix.plate, Materials.Steel), + 'E', MetaItems.EMITTER_MV.getStackForm(), + 'C', new UnificationEntry(OrePrefix.pipeHugeItem, Materials.SterlingSilver), + 'A', MetaItems.ROBOT_ARM_MV.getStackForm(), + 'H', MetaTileEntities.HULL[GTValues.MV].getStackForm()); + + // Quantum Storage Extender + ModHandler.addShapedRecipe(true, "quantum_storage_extender", + MetaTileEntities.QUANTUM_STORAGE_EXTENDER.getStackForm(4), + "PPP", "CHC", "PPP", + 'P', new UnificationEntry(OrePrefix.plate, Materials.Steel), + 'C', new UnificationEntry(OrePrefix.pipeSmallItem, Materials.SterlingSilver), + 'H', MetaTileEntities.HULL[GTValues.MV].getStackForm()); + // Super / Quantum Chests ModHandler.addShapedRecipe(true, "super_chest_lv", MetaTileEntities.QUANTUM_CHEST[0].getStackForm(), "CPC", "PFP", "CPC", 'C', new UnificationEntry(OrePrefix.circuit, Tier.LV), 'P', diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 098b51612ee..c3aaf8cd8d9 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -53,6 +53,13 @@ gregtech.multiblock.steam_oven.description=A Multi Smelter at the Steam Age. Req gregtech.multiblock.require_steam_parts=Requires Steam Hatches and Buses! gregtech.multiblock.steam_.duration_modifier=Takes §f1.5x §7base duration to process, not affected by number of items. +gregtech.top.quantum_status.label=Status: +gregtech.top.quantum_status.powered=§bOnline +gregtech.top.quantum_status.connected=§cNo Power +gregtech.top.quantum_status.disconnected=Not connected +gregtech.top.quantum_controller.no_hatches=§cNo Energy Hatches Connected +gregtech.top.quantum_controller.no_power=§cNo Power + gregtech.top.working_disabled=Working Disabled gregtech.top.energy_consumption=Using @@ -2479,6 +2486,10 @@ behavior.tricorder.debug_lag_count=Caused %s Lag Spike Warnings (anything taking behavior.tricorder.mte_owner=Owner: %s behavior.tricorder.mte_owner_offline=Owner is Offline or Offworld! behavior.tricorder.mte_owner_null=This wasn't placed by a player! +behavior.tricorder.quantum_controller.usage=Using %s EU/t (%s) +behavior.tricorder.quantum_controller.connected_items=Connected item storages: %s +behavior.tricorder.quantum_controller.connected_fluids=Connected fluid storages: %s +behavior.tricorder.quantum_storage.usage=Contributing %s EU/t to Quantum Controller metaitem.item_magnet.lv.name=Low Voltage Item Magnet metaitem.item_magnet.hv.name=High Voltage Item Magnet @@ -4355,6 +4366,7 @@ gregtech.machine.alarm.tooltip=Plays a Sound when given a Redstone signal #Quantum Chests gregtech.machine.quantum_chest.tooltip=Better than Storage Drawers +gregtech.machine.super_chest.ulv.name=Primitive Chest I gregtech.machine.super_chest.lv.name=Super Chest I gregtech.machine.super_chest.mv.name=Super Chest II gregtech.machine.super_chest.hv.name=Super Chest III @@ -4370,6 +4382,7 @@ gregtech.machine.quantum_chest.items_stored=Item Amount: #Quantum Tanks gregtech.machine.quantum_tank.tooltip=Compact place to store all your fluids gregtech.machine.quantum_tank.tooltip.voiding_enabled=Excess Fluid Voiding §aEnabled +gregtech.machine.super_tank.ulv.name=Primitive Tank I gregtech.machine.super_tank.lv.name=Super Tank I gregtech.machine.super_tank.mv.name=Super Tank II gregtech.machine.super_tank.hv.name=Super Tank III @@ -4381,6 +4394,16 @@ gregtech.machine.quantum_tank.zpm.name=Quantum Tank III gregtech.machine.quantum_tank.uv.name=Quantum Tank IV gregtech.machine.quantum_tank.uhv.name=Quantum Tank V +#Quantum Storage Controller +gregtech.machine.quantum_storage_controller.name=Quantum Storage Controller +gregtech.machine.quantum_storage_controller.tooltip=Heart of the Quantum Storage Network/nConnect Energy Hatches to power the Quantum Storage Network +gregtech.machine.quantum_storage_proxy.name=Quantum Storage Proxy +gregtech.machine.quantum_storage_proxy.tooltip=Proxies the Quantum Storage Network's inventory +gregtech.machine.quantum_storage_extender.name=Quantum Storage Extender +gregtech.machine.quantum_storage_extender.tooltip=Extends the Quantum Storage Network to other chests/tanks +gregtech.machine.quantum_storage.connected=Connected to Quantum Controller at [%d, %d, %d]/n/nClick to highlight the controller +gregtech.machine.quantum_storage.disconnected=Not Connected + #Buffers gregtech.machine.buffer.tooltip=A Small Buffer to store Items and Fluids gregtech.machine.buffer.lv.name=Basic Buffer diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active.png new file mode 100644 index 00000000000..bcaa1934780 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active.png.mcmeta new file mode 100644 index 00000000000..60af678259b --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active_emissive.png new file mode 100644 index 00000000000..f3d2b53db29 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active_emissive.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active_emissive.png.mcmeta new file mode 100644 index 00000000000..f70648e7b1b --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_active_emissive.png.mcmeta @@ -0,0 +1,14 @@ +{ + "ctm": { + "ctm_version": 1, + "type": "CTM", + "layer": "BLOOM", + "gregtech": true, + "textures": [ + "gregtech:blocks/casings/quantum/controller_active_emissive" + ] + }, + "animation":{ + "frametime":4 + } +} diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active.png new file mode 100644 index 00000000000..6c93d14ea6b Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active_emissive.png new file mode 100644 index 00000000000..10af88febdf Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active_emissive.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active_emissive.png.mcmeta new file mode 100644 index 00000000000..4e8c6493e99 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_active_emissive.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 8 + } +} diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_inactive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_inactive.png new file mode 100644 index 00000000000..6c93d14ea6b Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_front_inactive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_inactive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_inactive.png new file mode 100644 index 00000000000..2c3e0d025d4 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/controller_inactive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender.png new file mode 100644 index 00000000000..b79e381d3ef Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active.png new file mode 100644 index 00000000000..e77eec21401 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active_emissive.png new file mode 100644 index 00000000000..3e2be0d612a Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active_emissive.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active_emissive.png.mcmeta new file mode 100644 index 00000000000..66b15be410d --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/extender_active_emissive.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active.png new file mode 100644 index 00000000000..3e37ee5702a Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active_emissive.png new file mode 100644 index 00000000000..bd4e03ab408 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active_emissive.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active_emissive.png.mcmeta new file mode 100644 index 00000000000..ea715020dc5 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_active_emissive.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_inactive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_inactive.png new file mode 100644 index 00000000000..3e37ee5702a Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/proxy_inactive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_casing.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_casing.png new file mode 100644 index 00000000000..e3e9eda45ec Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_casing.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_connected.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_connected.png new file mode 100644 index 00000000000..979458b11ad Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_connected.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_connected_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_connected_emissive.png new file mode 100644 index 00000000000..e6ce137eee4 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_connected_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_disconnected.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_disconnected.png new file mode 100644 index 00000000000..d703813cf92 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_disconnected.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_powered.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_powered.png new file mode 100644 index 00000000000..767c0e84670 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_powered.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_powered_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_powered_emissive.png new file mode 100644 index 00000000000..2083500cae4 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/casings/quantum/quantum_indicator_powered_emissive.png differ