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 IQuantumStorage>storage) {
+ 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 IQuantumStorage>storage) {
+ 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 IQuantumStorage>storage) {
+ 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 IQuantumStorage>quantumStorage)) {
+ 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 IQuantumStorage>storage &&
+ (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