diff --git a/dependencies.gradle b/dependencies.gradle index 28dfe5bcb1c..9eaa03ab322 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -55,7 +55,7 @@ dependencies { devOnlyNonPublishable("com.github.GTNewHorizons:Infernal-Mobs:1.10.3-GTNH:dev") - compileOnlyApi("com.github.GTNewHorizons:Avaritia:1.78:dev") + devOnlyNonPublishable("com.github.GTNewHorizons:Avaritia:1.85:dev") compileOnlyApi('com.github.GTNewHorizons:Angelica:2.0.0-alpha11:dev') { transitive = false } compileOnlyApi("com.github.GTNewHorizons:AppleCore:3.3.9:dev") { transitive = false } diff --git a/repositories.gradle b/repositories.gradle index b1ad5ca3d09..2d81b69af84 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -24,4 +24,5 @@ repositories { includeGroup('net.glease') } } + mavenLocal() } diff --git a/src/main/java/gregtech/api/enums/ItemList.java b/src/main/java/gregtech/api/enums/ItemList.java index ec07be5fd25..ad8d3564613 100644 --- a/src/main/java/gregtech/api/enums/ItemList.java +++ b/src/main/java/gregtech/api/enums/ItemList.java @@ -2753,6 +2753,23 @@ public enum ItemList implements IItemContainer { CokeOvenCasing, CokeOvenHatch, + CompressedOutputBusLuV, + CompressedOutputBusZPM, + CompressedOutputBusUV, + CompressedOutputBusUHV, + CompressedOutputBusUEV, + CompressedOutputBusUIV, + CompressedOutputBusUMV, + CompressedOutputBusUXV, + + CompressedInputBusLuV, + CompressedInputBusZPM, + CompressedInputBusUV, + CompressedInputBusUHV, + CompressedInputBusUEV, + CompressedInputBusUIV, + CompressedInputBusUMV, + CompressedInputBusUXV, CircuitImprint_NanoProcessor, CircuitImprint_BasicCircuitBoard, CircuitImprint_NanoAssembly, @@ -2893,7 +2910,7 @@ public enum ItemList implements IItemContainer { Wrap_OpticalCPUContainmentHousings, Wrap_OpticallyCompatibleMemories, Wrap_LivingCrystalChips, - Wrap_LivingBioChips + Wrap_LivingBioChips, // semicolon after the comment to reduce merge conflicts ; diff --git a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java index d42bc32538b..065669f3130 100644 --- a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java +++ b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java @@ -741,6 +741,22 @@ public enum MetaTileEntityIDs { SOLAR_PANEL_UV(2740), VENDING_MACHINE_CONTROLLER(2741), VENDING_MACHINE_UPLINK_ME(2742), + HATCH_OUTPUT_BUS_COMPRESSED_1(2743), + HATCH_OUTPUT_BUS_COMPRESSED_2(2744), + HATCH_OUTPUT_BUS_COMPRESSED_3(2745), + HATCH_OUTPUT_BUS_COMPRESSED_4(2746), + HATCH_OUTPUT_BUS_QUANTUM_1(2747), + HATCH_OUTPUT_BUS_QUANTUM_2(2748), + HATCH_OUTPUT_BUS_QUANTUM_3(2749), + HATCH_OUTPUT_BUS_QUANTUM_4(2750), + HATCH_INPUT_BUS_COMPRESSED_1(2751), + HATCH_INPUT_BUS_COMPRESSED_2(2752), + HATCH_INPUT_BUS_COMPRESSED_3(2753), + HATCH_INPUT_BUS_COMPRESSED_4(2754), + HATCH_INPUT_BUS_QUANTUM_1(2755), + HATCH_INPUT_BUS_QUANTUM_2(2756), + HATCH_INPUT_BUS_QUANTUM_3(2757), + HATCH_INPUT_BUS_QUANTUM_4(2758), INDUSTRIAL_LASER_ENGRAVER_CONTROLLER(3004), INDUSTRIAL_COMPRESSOR_CONTROLLER(3005), HIP_COMPRESSOR_CONTROLLER(3006), diff --git a/src/main/java/gregtech/api/enums/OutputBusType.java b/src/main/java/gregtech/api/enums/OutputBusType.java index 59307c4cf1a..01b711fb028 100644 --- a/src/main/java/gregtech/api/enums/OutputBusType.java +++ b/src/main/java/gregtech/api/enums/OutputBusType.java @@ -6,9 +6,11 @@ public enum OutputBusType { Void, + CompressedFiltered, StandardFiltered, MECacheFiltered, MEFiltered, + CompressedUnfiltered, StandardUnfiltered, MECacheUnfiltered, MEUnfiltered, @@ -17,8 +19,8 @@ public enum OutputBusType { public boolean isFiltered() { return switch (this) { - case Void, StandardFiltered, MECacheFiltered, MEFiltered -> true; - case StandardUnfiltered, MECacheUnfiltered, MEUnfiltered -> false; + case Void, StandardFiltered, MECacheFiltered, MEFiltered, CompressedFiltered -> true; + case StandardUnfiltered, MECacheUnfiltered, MEUnfiltered, CompressedUnfiltered -> false; }; } } diff --git a/src/main/java/gregtech/api/gui/widgets/CommonWidgets.java b/src/main/java/gregtech/api/gui/widgets/CommonWidgets.java index 08f99c10d06..0f984703619 100644 --- a/src/main/java/gregtech/api/gui/widgets/CommonWidgets.java +++ b/src/main/java/gregtech/api/gui/widgets/CommonWidgets.java @@ -123,7 +123,8 @@ public static Widget> createCircuitSlot(PanelSyncManager syn IMetaTileEntity baseMachine) { if (baseMachine instanceof IConfigurationCircuitSupport circuitEnabled && circuitEnabled.allowSelectCircuit()) { IntSyncValue selectedSyncHandler = new IntSyncValue(() -> { - ItemStack selectedItem = baseMachine.getStackInSlot(circuitEnabled.getCircuitSlot()); + ItemStack selectedItem = baseMachine.getInventoryHandler() + .getStackInSlot(circuitEnabled.getCircuitSlot()); if (selectedItem != null && selectedItem.getItem() instanceof ItemIntegratedCircuit) { // selected index 0 == config 1 return selectedItem.getItemDamage() - 1; diff --git a/src/main/java/gregtech/api/metatileentity/CommonBaseMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/CommonBaseMetaTileEntity.java index 0d618f56cb8..0f8a5de6e02 100644 --- a/src/main/java/gregtech/api/metatileentity/CommonBaseMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/CommonBaseMetaTileEntity.java @@ -140,6 +140,9 @@ protected void saveMetaTileNBT(NBTTagCompound aNBT) { final NBTTagCompound tTag = new NBTTagCompound(); tTag.setInteger("IntSlot", i); tStack.writeToNBT(tTag); + if (tStack.stackSize > Byte.MAX_VALUE) { + tTag.setInteger("Count", tStack.stackSize); + } tItemList.appendTag(tTag); } } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/MTEHatchInputBusCompressed.java b/src/main/java/gregtech/api/metatileentity/implementations/MTEHatchInputBusCompressed.java new file mode 100644 index 00000000000..b30248d1fb6 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/MTEHatchInputBusCompressed.java @@ -0,0 +1,582 @@ +package gregtech.api.metatileentity.implementations; + +import static com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil.formatNumber; +import static net.minecraft.util.EnumChatFormatting.GOLD; +import static net.minecraft.util.EnumChatFormatting.GRAY; + +import java.util.List; +import java.util.stream.IntStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.Nullable; +import org.lwjgl.input.Keyboard; + +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.screen.UISettings; +import com.cleanroommc.modularui.utils.NumberFormat; +import com.cleanroommc.modularui.utils.item.IItemHandlerModifiable; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.gtnewhorizon.gtnhlib.capability.item.ItemSink; +import com.gtnewhorizon.gtnhlib.capability.item.ItemSource; +import com.gtnewhorizon.gtnhlib.util.ItemUtil; + +import appeng.api.AEApi; +import appeng.api.config.AccessRestriction; +import appeng.api.config.Actionable; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.MachineSource; +import appeng.api.storage.IExternalStorageHandler; +import appeng.api.storage.IMEInventory; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.IMEMonitorHandlerReceiver; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.util.item.AEItemStack; +import gregtech.GTMod; +import gregtech.api.enums.ItemList; +import gregtech.api.interfaces.IDataCopyable; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GTDataUtils; +import gregtech.api.util.GTUtility; +import gregtech.api.util.extensions.ArrayExt; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.common.gui.modularui.hatch.MTEHatchInputBusCompressedGui; +import gregtech.common.gui.modularui.util.ProxiedItemHandlerModifiable; +import gregtech.common.inventory.AEInventory; +import gregtech.common.tileentities.machines.IRecipeProcessingAwareHatch; + +public class MTEHatchInputBusCompressed extends MTEHatchInputBus + implements IMEMonitor, IRecipeProcessingAwareHatch, IDataCopyable { + + public final int slotCount; + public final long stackCapacity; + public long stackLimitOverride; + + private final AEInventory inventory; + private final IItemHandlerModifiable itemHandler; + + private final int[] busSlots; + + private int processing = 0; + + private ItemStack[] originalStacks = null, containedStacks = null; + + public MTEHatchInputBusCompressed(int id, String name, String nameRegional, int tier, long stackCapacity) { + super( + id, + name, + nameRegional, + tier, + 0, + ArrayExt.of( + "Item Input for Multiblocks", + "Capacity: " + GOLD + getSlots(tier) + GRAY + " slots", + "Each slot can hold " + GOLD + NumberFormat.AMOUNT_TEXT.format(stackCapacity) + GRAY + " stacks", + "Bus config can be saved and loaded via a data stick", + "Can only be automated with GT and AE", + "Contents are kept when broken")); + + this.slotCount = getSlots(tier); + this.stackCapacity = stackCapacity; + this.inventory = null; + this.busSlots = IntStream.range(0, slotCount) + .toArray(); + this.itemHandler = null; + } + + protected MTEHatchInputBusCompressed(MTEHatchInputBusCompressed prototype) { + super(prototype.mName, prototype.mTier, 1, prototype.mDescriptionArray, prototype.mTextures); + + this.slotCount = prototype.slotCount; + this.stackCapacity = prototype.stackCapacity; + this.stackLimitOverride = prototype.stackCapacity; + this.busSlots = prototype.busSlots; + + this.inventory = new BusInventory(slotCount); + + this.itemHandler = new ProxiedItemHandlerModifiable(inventory) { + + @Override + public int getSlots() { + return super.getSlots() + 1; + } + + @Override + public @Nullable ItemStack getStackInSlot(int slot) { + if (slot == getCircuitSlot()) return mInventory[0]; + + return super.getStackInSlot(slot); + } + + @Override + public void setStackInSlot(int slot, @Nullable ItemStack stack) { + if (slot == getCircuitSlot()) { + mInventory[0] = GTUtility.copyAmount(0, stack); + return; + } + + super.setStackInSlot(slot, stack); + } + }; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTEHatchInputBusCompressed(this); + } + + @Override + public boolean connectsToItemPipe(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public int getStackSizeLimit(int slot, @Nullable ItemStack stack) { + return GTUtility.longToInt(this.inventory.getAESlotLimit(slot, AEItemStack.create(stack))); + } + + @Override + public int getInventoryStackLimit() { + return getStackSizeLimit(-1, null); + } + + @Override + public int getCircuitSlot() { + return slotCount; + } + + @Override + public void startRecipeProcessing() { + if (processing == 0) { + originalStacks = GTDataUtils + .mapToArray(inventory.inventory, ItemStack[]::new, s -> s == null ? null : s.getItemStack()); + containedStacks = GTDataUtils.mapToArray(originalStacks, ItemStack[]::new, GTUtility::copy); + } + + processing++; + } + + @Override + public CheckRecipeResult endRecipeProcessing(MTEMultiBlockBase controller) { + processing--; + + if (processing == 0) { + for (int slotIndex = 0; slotIndex < slotCount; slotIndex++) { + ItemStack original = originalStacks[slotIndex]; + ItemStack contained = containedStacks[slotIndex]; + + if (original == null) continue; + + int delta = original.stackSize - (contained == null ? 0 : contained.stackSize); + + if (delta == 0) continue; + + if (delta < 0) { + GTMod.GT_FML_LOGGER.error( + "Compressed input bus somehow has more items in it than was original stored; this recipe will be cancelled (slot index={}, original={}, contained={}, delta={})", + slotIndex, + original, + contained, + delta); + controller.stopMachine(ShutDownReasonRegistry.CRITICAL_NONE); + return CheckRecipeResultRegistry.CRASH; + } + + IAEItemStack stack = inventory.getAEStackInSlot(slotIndex); + + if (stack == null || delta > stack.getStackSize()) { + GTMod.GT_FML_LOGGER.error( + "Compressed input bus somehow consumed more items than were available for this slot; this recipe will be cancelled (slot index={}, original={}, contained={}, delta={})", + slotIndex, + original, + contained, + delta); + controller.stopMachine(ShutDownReasonRegistry.CRITICAL_NONE); + return CheckRecipeResultRegistry.CRASH; + } + + stack.decStackSize(delta); + + inventory.setStackInSlot(slotIndex, stack.getStackSize() == 0 ? null : stack); + } + + originalStacks = null; + containedStacks = null; + } + + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @Override + public int getSizeInventory() { + return processing > 0 ? slotCount + 1 : 0; + } + + @Override + public ItemStack getStackInSlot(int slotIndex) { + if (processing > 0) { + if (slotIndex == getCircuitSlot()) return mInventory[0]; + + return GTDataUtils.getIndexSafe(containedStacks, slotIndex); + } else { + return null; + } + } + + @Override + public void setInventorySlotContents(int slotIndex, ItemStack toInsert) { + if (slotIndex == getCircuitSlot()) { + mInventory[0] = GTUtility.copyAmount(0, toInsert); + markDirty(); + return; + } + + if (GTUtility.isStackValid(toInsert)) { + inventory.insertItem(slotIndex, toInsert, false); + } + } + + @Override + public ItemStack decrStackSize(int index, int amount) { + return inventory.extractItem(index, amount, false); + } + + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemStack) { + return allowPutStack(getBaseMetaTileEntity(), slotIndex, ForgeDirection.UNKNOWN, itemStack); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity igte, int slotIndex, ForgeDirection side, ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity igte, int slotIndex, ForgeDirection side, ItemStack toInsert) { + if (slotIndex == getCircuitSlot()) return false; + if (side != ForgeDirection.UNKNOWN && side != getBaseMetaTileEntity().getFrontFacing()) return false; + if (mRecipeMap != null && !disableFilter && !mRecipeMap.containsInput(toInsert)) return false; + + IAEItemStack existing = inventory.getAEStackInSlot(slotIndex); + + if (existing != null) { + if (existing.getStackSize() >= inventory.getAESlotLimit(slotIndex, existing)) return false; + } + + if (!disableLimited) { + int containingSlot = inventory.indexOf(toInsert); + + if (containingSlot != -1) { + return containingSlot == slotIndex; + } + } + + return existing == null || existing.isSameType(toInsert); + } + + @Override + public IItemHandlerModifiable getInventoryHandler() { + return itemHandler; + } + + @Override + public IItemList getStorageList() { + return inventory.getStorageList(); + } + + @Override + public IItemList getAvailableItems(final IItemList out, int iteration) { + return inventory.getAvailableItems(out, iteration); + } + + @Override + public void addListener(IMEMonitorHandlerReceiver l, Object verificationToken) { + inventory.addListener(l, verificationToken); + } + + @Override + public void removeListener(IMEMonitorHandlerReceiver l) { + inventory.removeListener(l); + } + + @Override + public AccessRestriction getAccess() { + return inventory.getAccess(); + } + + @Override + public boolean isPrioritized(IAEItemStack input) { + return inventory.isPrioritized(input); + } + + @Override + public boolean canAccept(IAEItemStack input) { + return inventory.canAccept(input); + } + + @Override + public int getPriority() { + return inventory.getPriority(); + } + + @Override + public int getSlot() { + return inventory.getSlot(); + } + + @Override + public boolean validForPass(int i) { + return inventory.validForPass(i); + } + + @Override + public IAEItemStack injectItems(IAEItemStack input, Actionable type, BaseActionSource src) { + return inventory.injectItems(input, type, src); + } + + @Override + public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src) { + // Don't allow extractions + return null; + } + + @Override + public StorageChannel getChannel() { + return inventory.getChannel(); + } + + @Override + public void setItemNBT(NBTTagCompound nbt) { + super.setItemNBT(nbt); + + if (!inventory.getStorageList() + .isEmpty()) { + nbt.setTag("inv", inventory.writeToNBT(new NBTTagCompound())); + } + } + + @Override + public void addAdditionalTooltipInformation(ItemStack stack, List tooltip) { + super.addAdditionalTooltipInformation(stack, tooltip); + + NBTTagCompound tag = stack.getTagCompound(); + + if (tag != null && tag.hasKey("inv")) { + BusInventory inv = new BusInventory(this.slotCount); + inv.readFromNBT(tag.getCompoundTag("inv")); + + tooltip.add(""); + + if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + for (IAEItemStack stored : inv.getStorageList()) { + tooltip.add(stored.getDisplayName() + " x " + GOLD + formatNumber(stored.getStackSize())); + } + } else { + tooltip.add(GTUtility.translate("GT5U.gui.text.compressed_bus_stored_items")); + } + + tooltip.add(""); + } + } + + @Override + public void loadNBTData(NBTTagCompound tag) { + super.loadNBTData(tag); + + inventory.readFromNBT(tag.getCompoundTag("inv")); + stackLimitOverride = tag.getLong("stackLimitOverride"); + } + + @Override + public void saveNBTData(NBTTagCompound tag) { + super.saveNBTData(tag); + + tag.setTag("inv", inventory.writeToNBT(new NBTTagCompound())); + tag.setLong("stackLimitOverride", stackLimitOverride); + } + + protected void loadBusConfig(NBTTagCompound tag) { + stackLimitOverride = tag.getLong("stackLimitOverride"); + disableLimited = tag.getBoolean("disableLimited"); + disableFilter = tag.getBoolean("disableFilter"); + disableSort = tag.getBoolean("disableSort"); + + int circuit = tag.getInteger("circuit"); + + mInventory[0] = circuit == -1 ? null : GTUtility.getIntegratedCircuit(circuit); + } + + protected void saveBusConfig(NBTTagCompound tag) { + tag.setLong("stackLimitOverride", stackLimitOverride); + tag.setBoolean("disableLimited", disableLimited); + tag.setBoolean("disableFilter", disableFilter); + tag.setBoolean("disableSort", disableSort); + + tag.setInteger("circuit", mInventory[0] == null ? -1 : ItemUtil.getStackMeta(mInventory[0])); + } + + @Override + public boolean onRightclick(IGregTechTileEntity igte, EntityPlayer player) { + final ItemStack dataStick = player.inventory.getCurrentItem(); + + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) { + openGui(player); + return true; + } + + if (!pasteCopiedData(player, dataStick.stackTagCompound)) { + if (player.worldObj.isRemote) { + player.addChatMessage(new ChatComponentTranslation("GT5U.machines.output_bus.invalid")); + } + + return false; + } else { + if (player.worldObj.isRemote) { + player.addChatMessage(new ChatComponentTranslation("GT5U.machines.output_bus.loaded")); + } + + return true; + } + } + + @Override + public void onLeftclick(IGregTechTileEntity igte, EntityPlayer player) { + final ItemStack held = player.inventory.getCurrentItem(); + + if (!ItemList.Tool_DataStick.isStackEqual(held, false, true)) { + return; + } + + held.stackTagCompound = getCopiedData(player); + held.setStackDisplayName("Output Bus Configuration"); + player.addChatMessage(new ChatComponentTranslation("GT5U.machines.output_bus.saved")); + } + + @Override + public NBTTagCompound getCopiedData(EntityPlayer player) { + final NBTTagCompound nbt = new NBTTagCompound(); + nbt.setString("type", mName); + saveBusConfig(nbt); + return nbt; + } + + @Override + public boolean pasteCopiedData(EntityPlayer player, NBTTagCompound nbt) { + if (nbt == null || !mName.equals(nbt.getString("type"))) return false; + loadBusConfig(nbt); + return true; + } + + @Override + public String getCopiedDataIdentifier(EntityPlayer player) { + return mName; + } + + @Override + public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings uiSettings) { + return new MTEHatchInputBusCompressedGui(this).build(data, syncManager, uiSettings); + } + + public AEInventory getAEInventory() { + return inventory; + } + + @Override + protected ItemSource getItemSource(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing() ? inventory.getItemIO() : null; + } + + @Override + protected ItemSink getItemSink(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing() ? inventory.getItemIO() : null; + } + + public long getStackLimitOverride() { + return stackLimitOverride; + } + + public void setStackLimitOverride(long stackLimitOverride) { + this.stackLimitOverride = stackLimitOverride; + } + + class BusInventory extends AEInventory { + + public BusInventory(int slotCount) { + super(slotCount); + } + + @Override + public long getAESlotLimit(int slot, @Nullable IAEItemStack stack) { + int maxStack = stack == null ? 64 + : stack.getItemStack() + .getMaxStackSize(); + + return maxStack * stackLimitOverride; + } + + @Override + protected boolean allowPutStack(int slotIndex, IAEItemStack toInsert) { + IGregTechTileEntity igte = getBaseMetaTileEntity(); + + return MTEHatchInputBusCompressed.this.allowPutStack( + igte, + slotIndex, + ForgeDirection.UNKNOWN, + toInsert == null ? null : toInsert.getItemStack()); + } + + @Override + protected boolean allowPullStack(int slotIndex) { + return false; + } + + @Override + protected AEInventory copyImpl() { + return new MTEHatchInputBusCompressed.BusInventory(slotCount); + } + + @Override + public BaseActionSource getActionSource() { + return new MachineSource((BaseMetaTileEntity) getBaseMetaTileEntity()); + } + } + + public static void registerAEIntegration() { + AEApi.instance() + .registries() + .externalStorage() + .addExternalStorageInterface(new StorageHandler()); + } + + private static class StorageHandler implements IExternalStorageHandler { + + @Override + + public boolean canHandle(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource mySrc) { + return channel == StorageChannel.ITEMS && te instanceof BaseMetaTileEntity + && ((BaseMetaTileEntity) te).getMetaTileEntity() instanceof MTEHatchInputBusCompressed; + } + + @Override + + public IMEInventory getInventory(TileEntity te, ForgeDirection d, StorageChannel channel, + BaseActionSource src) { + if (channel == StorageChannel.ITEMS) { + return (MTEHatchInputBusCompressed) ((BaseMetaTileEntity) te).getMetaTileEntity(); + } + return null; + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/MTEHatchOutputBusCompressed.java b/src/main/java/gregtech/api/metatileentity/implementations/MTEHatchOutputBusCompressed.java new file mode 100644 index 00000000000..8102f2607d1 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/implementations/MTEHatchOutputBusCompressed.java @@ -0,0 +1,429 @@ +package gregtech.api.metatileentity.implementations; + +import static net.minecraft.util.EnumChatFormatting.GOLD; +import static net.minecraft.util.EnumChatFormatting.GRAY; + +import java.util.List; +import java.util.stream.IntStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.input.Keyboard; + +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.screen.UISettings; +import com.cleanroommc.modularui.utils.NumberFormat; +import com.cleanroommc.modularui.utils.item.IItemHandlerModifiable; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.gtnewhorizon.gtnhlib.capability.item.ItemSink; +import com.gtnewhorizon.gtnhlib.capability.item.ItemSource; +import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil; + +import appeng.api.AEApi; +import appeng.api.config.AccessRestriction; +import appeng.api.config.Actionable; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.MachineSource; +import appeng.api.storage.IExternalStorageHandler; +import appeng.api.storage.IMEInventory; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.IMEMonitorHandlerReceiver; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.util.InventoryAdaptor; +import appeng.util.inv.IMEAdaptor; +import appeng.util.item.AEItemStack; +import gregtech.api.enums.OutputBusType; +import gregtech.api.interfaces.IOutputBusTransaction; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.util.GTUtility; +import gregtech.api.util.extensions.ArrayExt; +import gregtech.common.gui.modularui.hatch.MTEHatchOutputBusCompressedGui; +import gregtech.common.inventory.AEInventory; + +public class MTEHatchOutputBusCompressed extends MTEHatchOutputBus implements IMEMonitor { + + public final int slotCount; + public final long stackCapacity; + public long stackLimitOverride; + + private final AEInventory inventory; + + private final int[] busSlots; + + public MTEHatchOutputBusCompressed(int id, String name, String nameRegional, int tier, long stackCapacity) { + super( + id, + name, + nameRegional, + tier, + ArrayExt.of( + "Item Output for Multiblocks", + "Capacity: " + GOLD + getSlots(tier) + GRAY + " slots", + "Each slot can hold " + GOLD + NumberFormat.AMOUNT_TEXT.format(stackCapacity) + GRAY + " stacks", + "Bus config can be saved and loaded via a data stick", + "Can only be automated with GT and AE", + "Contents are kept when broken"), + 0); + + this.slotCount = getSlots(tier); + this.stackCapacity = stackCapacity; + this.inventory = null; + this.busSlots = IntStream.range(0, slotCount) + .toArray(); + } + + protected MTEHatchOutputBusCompressed(MTEHatchOutputBusCompressed prototype) { + super(prototype.mName, prototype.mTier, 0, prototype.mDescriptionArray, prototype.mTextures); + + this.slotCount = prototype.slotCount; + this.stackCapacity = prototype.stackCapacity; + this.stackLimitOverride = prototype.stackCapacity; + this.busSlots = prototype.busSlots; + + this.inventory = new BusInventory(slotCount); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTEHatchOutputBusCompressed(this); + } + + public AEInventory getAEInventory() { + return inventory; + } + + public long getStackLimitOverride() { + return stackLimitOverride; + } + + public void setStackLimitOverride(long stackLimitOverride) { + this.stackLimitOverride = stackLimitOverride; + } + + @Override + public boolean connectsToItemPipe(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public int getStackSizeLimit(int slot, @Nullable ItemStack stack) { + return GTUtility.longToInt(this.inventory.getAESlotLimit(slot, AEItemStack.create(stack))); + } + + @Override + public int getInventoryStackLimit() { + return getStackSizeLimit(-1, null); + } + + @Override + protected int getStackTransferAmount() { + return slotCount; + } + + @Override + public OutputBusType getBusType() { + return lockedItem == null ? OutputBusType.CompressedUnfiltered : OutputBusType.CompressedFiltered; + } + + @Override + public boolean storePartial(ItemStack stack, boolean simulate) { + if (!simulate) markDirty(); + + IAEItemStack rejected = inventory.injectItems( + AEItemStack.create(stack), + simulate ? Actionable.SIMULATE : Actionable.MODULATE, + new MachineSource((BaseMetaTileEntity) getBaseMetaTileEntity())); + + stack.stackSize = (int) (rejected == null ? 0 : rejected.getStackSize()); + + return stack.stackSize == 0; + } + + @Override + public IItemHandlerModifiable getInventoryHandler() { + return inventory; + } + + @Override + public IItemList getStorageList() { + return inventory.getStorageList(); + } + + @Override + public IItemList getAvailableItems(final IItemList out, int iteration) { + return inventory.getAvailableItems(out, iteration); + } + + @Override + public @Nullable T getCapability(@NotNull Class capability, @NotNull ForgeDirection side) { + if (capability == InventoryAdaptor.class && side == getBaseMetaTileEntity().getFrontFacing()) { + return capability.cast(new IMEAdaptor(inventory, inventory.getActionSource())); + } + + return super.getCapability(capability, side); + } + + @Override + public void addListener(IMEMonitorHandlerReceiver l, Object verificationToken) { + inventory.addListener(l, verificationToken); + } + + @Override + public void removeListener(IMEMonitorHandlerReceiver l) { + inventory.removeListener(l); + } + + @Override + public AccessRestriction getAccess() { + return inventory.getAccess(); + } + + @Override + public boolean isPrioritized(IAEItemStack input) { + return inventory.isPrioritized(input); + } + + @Override + public boolean canAccept(IAEItemStack input) { + return inventory.canAccept(input); + } + + @Override + public int getPriority() { + return inventory.getPriority(); + } + + @Override + public int getSlot() { + return inventory.getSlot(); + } + + @Override + public boolean validForPass(int i) { + return inventory.validForPass(i); + } + + @Override + public IAEItemStack injectItems(IAEItemStack input, Actionable type, BaseActionSource src) { + // Don't allow insertions + return input; + } + + @Override + public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src) { + return inventory.extractItems(request, mode, src); + } + + @Override + public StorageChannel getChannel() { + return inventory.getChannel(); + } + + @Override + public void setItemNBT(NBTTagCompound nbt) { + super.setItemNBT(nbt); + + if (!inventory.getStorageList() + .isEmpty()) { + nbt.setTag("inv", inventory.writeToNBT(new NBTTagCompound())); + } + } + + @Override + public void addAdditionalTooltipInformation(ItemStack stack, List tooltip) { + super.addAdditionalTooltipInformation(stack, tooltip); + + NBTTagCompound tag = stack.getTagCompound(); + + if (tag != null && tag.hasKey("inv")) { + BusInventory inv = new BusInventory(this.slotCount); + inv.readFromNBT(tag.getCompoundTag("inv")); + + if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + for (IAEItemStack stored : inv.getStorageList()) { + tooltip.add(stored.getDisplayName() + " x " + NumberFormatUtil.formatNumber(stored.getStackSize())); + } + } else { + tooltip.add(GTUtility.translate("GT5U.gui.text.compressed_bus_stored_items")); + } + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + + inventory.readFromNBT(aNBT.getCompoundTag("inv")); + loadBusConfig(aNBT); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + + aNBT.setTag("inv", inventory.writeToNBT(new NBTTagCompound())); + saveBusConfig(aNBT); + } + + protected void loadBusConfig(NBTTagCompound tag) { + stackLimitOverride = tag.getLong("stackLimitOverride"); + } + + protected void saveBusConfig(NBTTagCompound tag) { + tag.setLong("stackLimitOverride", stackLimitOverride); + } + + @Override + public NBTTagCompound getCopiedData(EntityPlayer player) { + final NBTTagCompound nbt = super.getCopiedData(player); + saveBusConfig(nbt); + return nbt; + } + + @Override + public boolean pasteCopiedData(EntityPlayer player, NBTTagCompound nbt) { + if (super.pasteCopiedData(player, nbt)) { + loadBusConfig(nbt); + return true; + } else { + return false; + } + } + + @Override + protected boolean useMui2() { + return true; + } + + @Override + public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings uiSettings) { + return new MTEHatchOutputBusCompressedGui(this).build(data, syncManager, uiSettings); + } + + @Override + public IOutputBusTransaction createTransaction() { + return new CompressedOutputBusTransaction(); + } + + @Override + protected ItemSource getItemSource(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing() ? inventory.getItemIO() : null; + } + + @Override + protected ItemSink getItemSink(ForgeDirection side) { + return null; + } + + class BusInventory extends AEInventory { + + public BusInventory(int slotCount) { + super(slotCount); + } + + @Override + public long getAESlotLimit(int slot, @Nullable IAEItemStack stack) { + int maxStack = stack == null ? 64 + : stack.getItemStack() + .getMaxStackSize(); + + return maxStack * stackLimitOverride; + } + + @Override + protected AEInventory copyImpl() { + return new BusInventory(slotCount); + } + + @Override + public BaseActionSource getActionSource() { + return new MachineSource((BaseMetaTileEntity) getBaseMetaTileEntity()); + } + } + + class CompressedOutputBusTransaction implements IOutputBusTransaction { + + private final AEInventory inventory; + + private boolean active = true; + + CompressedOutputBusTransaction() { + inventory = getBus().inventory.copy(); + } + + @Override + public MTEHatchOutputBusCompressed getBus() { + return MTEHatchOutputBusCompressed.this; + } + + @Override + public boolean storePartial(GTUtility.ItemId id, ItemStack stack) { + if (!active) throw new IllegalStateException("Cannot add to a transaction after committing it"); + + IAEItemStack rejected = inventory.injectItems(AEItemStack.create(stack), Actionable.MODULATE, null); + + stack.stackSize = rejected == null ? 0 : (int) rejected.getStackSize(); + + return false; + } + + @Override + public void completeItem(GTUtility.ItemId id) { + // Do nothing + } + + @Override + public boolean hasAvailableSpace() { + return true; + } + + @Override + public void commit() { + for (int i = 0; i < slotCount; i++) { + getBus().inventory.setStackInSlot(i, this.inventory.getAEStackInSlot(i)); + } + + getBus().markDirty(); + + active = false; + } + } + + public static void registerAEIntegration() { + AEApi.instance() + .registries() + .externalStorage() + .addExternalStorageInterface(new StorageHandler()); + } + + private static class StorageHandler implements IExternalStorageHandler { + + @Override + + public boolean canHandle(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource mySrc) { + return channel == StorageChannel.ITEMS && te instanceof BaseMetaTileEntity + && ((BaseMetaTileEntity) te).getMetaTileEntity() instanceof MTEHatchOutputBusCompressed; + } + + @Override + + public IMEInventory getInventory(TileEntity te, ForgeDirection d, StorageChannel channel, + BaseActionSource src) { + if (channel == StorageChannel.ITEMS) { + return (MTEHatchOutputBusCompressed) ((BaseMetaTileEntity) te).getMetaTileEntity(); + } + return null; + } + } +} diff --git a/src/main/java/gregtech/api/modularui2/GTGuiTextures.java b/src/main/java/gregtech/api/modularui2/GTGuiTextures.java index 63c06ef0147..904f9d2aab4 100644 --- a/src/main/java/gregtech/api/modularui2/GTGuiTextures.java +++ b/src/main/java/gregtech/api/modularui2/GTGuiTextures.java @@ -390,6 +390,13 @@ public static void init() {} GTTextureIds.OVERLAY_SLOT_BLOCK_STEEL, GTTextureIds.OVERLAY_SLOT_BLOCK_PRIMITIVE) .build(); + public static final UITexture OVERLAY_SLOT_FILTER = UITexture.builder() + .location(GregTech.ID, "gui/overlay_slot/filter") + .fullImage() + .imageSize(18, 18) + .canApplyTheme() + .name("overlay_slot/filter") + .build(); public static final UITexture OVERLAY_SLOT_ARROW_4 = UITexture.fullImage(GTPlusPlus.ID, "gui/overlay_slot/arrow_4"); diff --git a/src/main/java/gregtech/api/util/GTUtility.java b/src/main/java/gregtech/api/util/GTUtility.java index 6eabb1ea483..041fd19da36 100644 --- a/src/main/java/gregtech/api/util/GTUtility.java +++ b/src/main/java/gregtech/api/util/GTUtility.java @@ -813,7 +813,7 @@ public static boolean compactInventory(List inv, ItemStackSizeCalcula insert++; } - return didSomething.getValue(); + return didSomething.booleanValue(); } public static void swapSlots(IInventory inv, int a, int b) { diff --git a/src/main/java/gregtech/api/util/item/GhostCircuitItemStackHandler.java b/src/main/java/gregtech/api/util/item/GhostCircuitItemStackHandler.java index 3ed65b3d4d9..5083fdda06f 100644 --- a/src/main/java/gregtech/api/util/item/GhostCircuitItemStackHandler.java +++ b/src/main/java/gregtech/api/util/item/GhostCircuitItemStackHandler.java @@ -8,7 +8,6 @@ import gregtech.api.interfaces.IConfigurationCircuitSupport; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; -import gregtech.api.metatileentity.CommonMetaTileEntity; import gregtech.api.util.GTUtility; import gregtech.common.items.ItemIntegratedCircuit; @@ -20,17 +19,14 @@ public class GhostCircuitItemStackHandler implements IItemHandlerModifiable { public static final int NO_CONFIG = -1; - private final ItemStack[] inventory; + private final IItemHandlerModifiable inventory; private final int circuitSlot; public GhostCircuitItemStackHandler(IMetaTileEntity mte) { - if (!(mte instanceof CommonMetaTileEntity cmte)) { - throw new IllegalArgumentException("Unknown MetaTileEntity: " + mte); - } - this.inventory = cmte.mInventory; if (!(mte instanceof IConfigurationCircuitSupport ccs)) { throw new IllegalArgumentException(mte + " does not implement IConfigurationCircuitSupport"); } + this.inventory = mte.getInventoryHandler(); this.circuitSlot = ccs.getCircuitSlot(); } @@ -38,7 +34,7 @@ public GhostCircuitItemStackHandler(IMetaTileEntity mte) { * Returns whether circuit item is present. */ public boolean hasCircuit() { - return inventory[circuitSlot] != null; + return inventory.getStackInSlot(circuitSlot) != null; } /** @@ -46,7 +42,8 @@ public boolean hasCircuit() { */ public int getCircuitConfig() { if (hasCircuit()) { - return inventory[circuitSlot].getItemDamage(); + return inventory.getStackInSlot(circuitSlot) + .getItemDamage(); } return NO_CONFIG; } @@ -56,9 +53,9 @@ public int getCircuitConfig() { */ public void setCircuitConfig(int config) { if (config == NO_CONFIG) { - inventory[circuitSlot] = null; + inventory.setStackInSlot(circuitSlot, null); } else if (config >= 1 && config <= ItemIntegratedCircuit.MAX_CIRCUIT_NUMBER) { - inventory[circuitSlot] = GTUtility.getIntegratedCircuit(config); + inventory.setStackInSlot(circuitSlot, GTUtility.getIntegratedCircuit(config)); } else { throw new IllegalArgumentException("Invalid circuit config: " + config); } @@ -71,7 +68,7 @@ public void setStackInSlot(int slot, @Nullable ItemStack stack) { if (stack != null) { stack.stackSize = 0; } - inventory[circuitSlot] = stack; + inventory.setStackInSlot(circuitSlot, stack); } } @@ -84,7 +81,7 @@ public int getSlots() { @Override public ItemStack getStackInSlot(int slot) { validateSlot(slot); - return inventory[circuitSlot]; + return inventory.getStackInSlot(circuitSlot); } @Nullable diff --git a/src/main/java/gregtech/api/util/item/PhantomSingleSlotItemStackHandler.java b/src/main/java/gregtech/api/util/item/PhantomSingleSlotItemStackHandler.java new file mode 100644 index 00000000000..7c9dd730d44 --- /dev/null +++ b/src/main/java/gregtech/api/util/item/PhantomSingleSlotItemStackHandler.java @@ -0,0 +1,53 @@ +package gregtech.api.util.item; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.Nullable; + +import com.cleanroommc.modularui.utils.item.IItemHandlerModifiable; + +public class PhantomSingleSlotItemStackHandler implements IItemHandlerModifiable { + + private final Supplier getter; + private final Consumer setter; + + public PhantomSingleSlotItemStackHandler(Supplier getter, Consumer setter) { + this.getter = getter; + this.setter = setter; + } + + @Override + public void setStackInSlot(int slot, @Nullable ItemStack stack) { + if (slot == 0) { + setter.accept(stack); + } + } + + @Override + public int getSlots() { + return 1; + } + + @Override + public @Nullable ItemStack getStackInSlot(int slot) { + return slot == 0 ? getter.get() : null; + } + + @Override + public @Nullable ItemStack insertItem(int slot, @Nullable ItemStack stack, boolean simulate) { + return null; + } + + @Override + public @Nullable ItemStack extractItem(int slot, int amount, boolean simulate) { + return null; + } + + @Override + public int getSlotLimit(int slot) { + return 0; + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/hatch/MTEHatchInputBusCompressedGui.java b/src/main/java/gregtech/common/gui/modularui/hatch/MTEHatchInputBusCompressedGui.java new file mode 100644 index 00000000000..552da97b59e --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/hatch/MTEHatchInputBusCompressedGui.java @@ -0,0 +1,177 @@ +package gregtech.common.gui.modularui.hatch; + +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.util.MathHelper; + +import com.cleanroommc.modularui.api.IPanelHandler; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.api.widget.IWidget; +import com.cleanroommc.modularui.drawable.UITexture; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.value.sync.BooleanSyncValue; +import com.cleanroommc.modularui.value.sync.LongSyncValue; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.widget.ParentWidget; +import com.cleanroommc.modularui.widgets.ButtonWidget; +import com.cleanroommc.modularui.widgets.SlotGroupWidget; +import com.cleanroommc.modularui.widgets.ToggleButton; +import com.cleanroommc.modularui.widgets.layout.Column; +import com.cleanroommc.modularui.widgets.layout.Flow; +import com.cleanroommc.modularui.widgets.layout.Row; +import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget; + +import gregtech.api.metatileentity.implementations.MTEHatchInputBusCompressed; +import gregtech.api.modularui2.GTGuiTextures; +import gregtech.api.util.GTUtility; +import gregtech.api.util.StringUtils; +import gregtech.common.gui.modularui.hatch.base.MTEHatchBaseGui; +import gregtech.common.gui.modularui.synchandler.NBTSerializableSyncHandler; +import gregtech.common.gui.modularui.util.AEItemSlot; +import gregtech.common.inventory.AEInventory; + +public class MTEHatchInputBusCompressedGui extends MTEHatchBaseGui { + + public MTEHatchInputBusCompressedGui(MTEHatchInputBusCompressed hatch) { + super(hatch); + } + + @Override + protected boolean supportsLeftCornerFlow() { + return true; + } + + // just in case any subclasses want to override this + // value corresponds to the size of any side of the slot group grid + protected int getDimension() { + return MathHelper.ceiling_double_int( + Math.sqrt( + hatch.getAEInventory() + .getSlots())); + } + + @Override + protected Flow createLeftCornerFlow(ModularPanel panel, PanelSyncManager syncManager) { + BooleanSyncValue stackSync = new BooleanSyncValue(() -> !hatch.disableSort, val -> hatch.disableSort = !val); + BooleanSyncValue insertionSync = new BooleanSyncValue( + () -> !hatch.disableLimited, + val -> hatch.disableLimited = !val); + return super.createLeftCornerFlow(panel, syncManager) + .child( + createToggleButton( + stackSync, + GTGuiTextures.OVERLAY_BUTTON_SORTING_MODE, + "GT5U.machines.sorting_mode.tooltip")) + .child( + createToggleButton( + insertionSync, + GTGuiTextures.OVERLAY_BUTTON_ONE_STACK_LIMIT, + "GT5U.machines.one_stack_limit.tooltip")) + .child(createSettingsButton(syncManager, panel)); + } + + protected IWidget createSettingsButton(PanelSyncManager syncManager, ModularPanel parent) { + IPanelHandler settingsPanel = syncManager.syncedPanel( + "busSettings", + true, + (p_syncManager, syncHandler) -> createSettingsPanel(p_syncManager, parent)); + return new ButtonWidget<>().size(18, 18) + .overlay(GTGuiTextures.OVERLAY_BUTTON_SCREWDRIVER) + .onMousePressed(d -> { + if (!settingsPanel.isPanelOpen()) { + settingsPanel.openPanel(); + } else { + settingsPanel.closePanel(); + } + return true; + }) + .tooltipBuilder(t -> t.addLine(IKey.lang("GT5U.gui.button.compressed_bus_settings"))) + .tooltipShowUpTimer(TOOLTIP_DELAY); + } + + private ModularPanel createSettingsPanel(PanelSyncManager syncManager, ModularPanel parent) { + LongSyncValue capacitySyncer = new LongSyncValue(hatch::getStackLimitOverride, hatch::setStackLimitOverride); + + // spotless:off + return new ModularPanel("busSettings") + .relative(parent) + .rightRel(1) + .bottom(50) + .size(150, 60) + .child(new Column() + .sizeRel(1) + .padding(3) + .align(Alignment.TopCenter) + .child(IKey.lang("GT5U.gui.text.bus_settings") + .asWidget() + .marginBottom(4)) + .child(new Row() + .alignX(Alignment.Center) + .size(140, 20) + .child(IKey.lang("GT5U.gui.text.stack_capacity") + .asWidget() + .marginRight(4)) + .child(new TextFieldWidget() + .setNumbersLong(() -> 1L, () -> hatch.stackCapacity) + .value(capacitySyncer) + .setScrollValues(1d, 4d, 64d)))); + // spotless:on + } + + private final int BUTTON_SIZE = 18; + + @Override + protected int getBasePanelHeight() { + // we subtract 4 from the dimension before adding this value as a 4x4 slot grid is the maximum that fits on the + // default panel + return super.getBasePanelHeight() + Math.max(0, BUTTON_SIZE * (this.getDimension() - 4) + 18); + } + + @Override + protected int getBasePanelWidth() { + // we subtract 9 from the dimension before adding this value as a 9x9 slot grid is the maximum that fits on the + // default width panel + return super.getBasePanelWidth() + Math.max(0, BUTTON_SIZE * (this.getDimension() - 9)); + } + + @Override + protected ParentWidget createContentSection(ModularPanel panel, PanelSyncManager syncManager) { + return super.createContentSection(panel, syncManager).child(createSlots(syncManager)); + } + + protected SlotGroupWidget createSlots(PanelSyncManager syncManager) { + + AEInventory inv = hatch.getAEInventory(); + + int slotCount = inv.getSlots(); + + final int width = MathHelper.ceiling_double_int(Math.sqrt(slotCount)); + syncManager.registerSlotGroup("item_inv", width); + + List matrix = new ArrayList<>(); + + for (int i = 0; i < slotCount; i += width) { + matrix.add(StringUtils.getRepetitionOf('s', Math.min(slotCount - i, width))); + } + + syncManager.syncValue("inventory", new NBTSerializableSyncHandler<>(hatch::getAEInventory)); + + return SlotGroupWidget.builder() + .matrix(matrix.toArray(new String[0])) + .key('s', index -> new AEItemSlot(syncManager, "item_inv", inv, index).setDumpable(true)) + .build() + .coverChildren() + .marginTop(BUTTON_SIZE / 2 * (4 - this.getDimension())) + .horizontalCenter(); + } + + private ToggleButton createToggleButton(BooleanSyncValue syncValue, UITexture texture, String key) { + return new ToggleButton().value(syncValue) + .overlay(texture) + .addTooltipLine(GTUtility.translate(key)); + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/hatch/MTEHatchOutputBusCompressedGui.java b/src/main/java/gregtech/common/gui/modularui/hatch/MTEHatchOutputBusCompressedGui.java new file mode 100644 index 00000000000..d15281abfd4 --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/hatch/MTEHatchOutputBusCompressedGui.java @@ -0,0 +1,155 @@ +package gregtech.common.gui.modularui.hatch; + +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.util.MathHelper; + +import com.cleanroommc.modularui.api.IPanelHandler; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.api.widget.IWidget; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.value.sync.LongSyncValue; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.widget.ParentWidget; +import com.cleanroommc.modularui.widgets.ButtonWidget; +import com.cleanroommc.modularui.widgets.SlotGroupWidget; +import com.cleanroommc.modularui.widgets.layout.Column; +import com.cleanroommc.modularui.widgets.layout.Flow; +import com.cleanroommc.modularui.widgets.layout.Row; +import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget; + +import gregtech.api.metatileentity.implementations.MTEHatchOutputBusCompressed; +import gregtech.api.modularui2.GTGuiTextures; +import gregtech.api.util.StringUtils; +import gregtech.common.gui.modularui.hatch.base.MTEHatchBaseGui; +import gregtech.common.gui.modularui.synchandler.NBTSerializableSyncHandler; +import gregtech.common.gui.modularui.util.AEItemSlot; +import gregtech.common.gui.modularui.util.FilterSlot; +import gregtech.common.inventory.AEInventory; + +public class MTEHatchOutputBusCompressedGui extends MTEHatchBaseGui { + + public MTEHatchOutputBusCompressedGui(MTEHatchOutputBusCompressed hatch) { + super(hatch); + } + + @Override + protected boolean supportsLeftCornerFlow() { + return true; + } + + // just in case any subclasses want to override this + // value corresponds to the size of any side of the slot group grid + protected int getDimension() { + return MathHelper.ceiling_double_int( + Math.sqrt( + hatch.getAEInventory() + .getSlots())); + } + + @Override + protected Flow createLeftCornerFlow(ModularPanel panel, PanelSyncManager syncManager) { + return super.createLeftCornerFlow(panel, syncManager) + .child(new FilterSlot(hatch::getLockedItem, hatch::setLockedItem)) + .child(createSettingsButton(syncManager, panel)); + } + + protected IWidget createSettingsButton(PanelSyncManager syncManager, ModularPanel parent) { + IPanelHandler settingsPanel = syncManager.syncedPanel( + "busSettings", + true, + (p_syncManager, syncHandler) -> createSettingsPanel(p_syncManager, parent)); + return new ButtonWidget<>().size(18, 18) + .overlay(GTGuiTextures.OVERLAY_BUTTON_SCREWDRIVER) + .onMousePressed(d -> { + if (!settingsPanel.isPanelOpen()) { + settingsPanel.openPanel(); + } else { + settingsPanel.closePanel(); + } + return true; + }) + .tooltipBuilder(t -> t.addLine(IKey.lang("GT5U.gui.button.compressed_bus_settings"))) + .tooltipShowUpTimer(TOOLTIP_DELAY); + } + + private ModularPanel createSettingsPanel(PanelSyncManager syncManager, ModularPanel parent) { + LongSyncValue capacitySyncer = new LongSyncValue(hatch::getStackLimitOverride, hatch::setStackLimitOverride); + + // spotless:off + return new ModularPanel("busSettings") + .relative(parent) + .rightRel(1) + .bottom(50) + .size(150, 60) + .child(new Column() + .sizeRel(1) + .padding(3) + .align(Alignment.TopCenter) + .child(IKey.lang("GT5U.gui.text.bus_settings") + .asWidget() + .marginBottom(4)) + .child(new Row() + .alignX(Alignment.Center) + .size(140, 20) + .child(IKey.lang("GT5U.gui.text.stack_capacity") + .asWidget() + .marginRight(4)) + .child(new TextFieldWidget() + .setNumbersLong(() -> 1L, () -> hatch.stackCapacity) + .value(capacitySyncer) + .setScrollValues(1d, 4d, 64d)))); + // spotless:on + } + + private final int BUTTON_SIZE = 18; + + @Override + protected int getBasePanelHeight() { + // we subtract 4 from the dimension before adding this value as a 4x4 slot grid is the maximum that fits on the + // default panel + return super.getBasePanelHeight() + Math.max(0, BUTTON_SIZE * (this.getDimension() - 4) + 18); + } + + @Override + protected int getBasePanelWidth() { + // we subtract 9 from the dimension before adding this value as a 9x9 slot grid is the maximum that fits on the + // default width panel + return super.getBasePanelWidth() + Math.max(0, BUTTON_SIZE * (this.getDimension() - 9)); + } + + @Override + protected ParentWidget createContentSection(ModularPanel panel, PanelSyncManager syncManager) { + return super.createContentSection(panel, syncManager).child(createSlots(syncManager)); + } + + protected SlotGroupWidget createSlots(PanelSyncManager syncManager) { + + AEInventory inv = hatch.getAEInventory(); + + int slotCount = inv.getSlots(); + + final int width = MathHelper.ceiling_double_int(Math.sqrt(slotCount)); + syncManager.registerSlotGroup("item_inv", width); + + List matrix = new ArrayList<>(); + + for (int i = 0; i < slotCount; i += width) { + matrix.add(StringUtils.getRepetitionOf('s', Math.min(slotCount - i, width))); + } + + syncManager.syncValue("inventory", new NBTSerializableSyncHandler<>(hatch::getAEInventory)); + + return SlotGroupWidget.builder() + .matrix(matrix.toArray(new String[0])) + .key('s', index -> new AEItemSlot(syncManager, "item_inv", inv, index).setDumpable(true)) + .build() + .coverChildren() + .marginTop(BUTTON_SIZE / 2 * (4 - width)) + .horizontalCenter(); + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/synchandler/NBTSerializableSyncHandler.java b/src/main/java/gregtech/common/gui/modularui/synchandler/NBTSerializableSyncHandler.java new file mode 100644 index 00000000000..1d43bf2e9c8 --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/synchandler/NBTSerializableSyncHandler.java @@ -0,0 +1,50 @@ +package gregtech.common.gui.modularui.synchandler; + +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import net.minecraft.nbt.NBTTagCompound; + +import com.cleanroommc.modularui.utils.item.INBTSerializable; + +public class NBTSerializableSyncHandler> extends NBTTagSyncHandler { + + public NBTSerializableSyncHandler(Supplier ctor, Supplier getter, Consumer setter) { + super( + () -> getter.get() + .serializeNBT(), + tag -> { + T value = ctor.get(); + value.deserializeNBT(tag); + setter.accept(value); + }); + } + + public NBTSerializableSyncHandler(Supplier getter, Consumer setter) { + super( + () -> getter.get() + .serializeNBT(), + tag -> { + T value = getter.get(); + value.deserializeNBT(tag); + setter.accept(value); + }); + } + + public NBTSerializableSyncHandler(Supplier ref) { + super( + () -> ref.get() + .serializeNBT(), + tag -> { + T value = ref.get(); + value.deserializeNBT(tag); + }); + } + + @Override + public NBTSerializableSyncHandler withEqualityFunc(BiPredicate equality) { + super.withEqualityFunc(equality); + return this; + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/synchandler/NBTTagSyncHandler.java b/src/main/java/gregtech/common/gui/modularui/synchandler/NBTTagSyncHandler.java new file mode 100644 index 00000000000..7d1c1055037 --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/synchandler/NBTTagSyncHandler.java @@ -0,0 +1,79 @@ +package gregtech.common.gui.modularui.synchandler; + +import java.io.IOException; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +import com.cleanroommc.modularui.value.sync.ValueSyncHandler; + +public class NBTTagSyncHandler extends ValueSyncHandler { + + private final Supplier getter; + private final Consumer setter; + + private BiPredicate equality = Object::equals; + + private NBTTagCompound cache; + + public NBTTagSyncHandler(Supplier getter, Consumer setter) { + this.getter = getter; + this.setter = setter; + } + + public NBTTagSyncHandler withEqualityFunc(BiPredicate equality) { + this.equality = equality; + return this; + } + + @Override + public Class getValueType() { + return NBTTagCompound.class; + } + + @Override + public void setValue(NBTTagCompound value, boolean setSource, boolean sync) { + this.cache = value; + if (setSource && this.setter != null) { + this.setter.accept(value); + } + if (sync) { + sync(0, this::write); + } + } + + @Override + public boolean updateCacheFromSource(boolean isFirstSync) { + NBTTagCompound value = this.getter.get(); + + if (isFirstSync || !equality.test(value, cache)) { + setValue(value, false, false); + return true; + } + + return false; + } + + @Override + public void notifyUpdate() { + setValue(this.getter.get(), false, true); + } + + @Override + public void write(PacketBuffer buffer) throws IOException { + buffer.writeNBTTagCompoundToBuffer(this.getter.get()); + } + + @Override + public void read(PacketBuffer buffer) throws IOException { + setValue(buffer.readNBTTagCompoundFromBuffer(), true, false); + } + + @Override + public NBTTagCompound getValue() { + return cache; + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/util/AEItemSlot.java b/src/main/java/gregtech/common/gui/modularui/util/AEItemSlot.java new file mode 100644 index 00000000000..4eb59d4f01b --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/util/AEItemSlot.java @@ -0,0 +1,106 @@ +package gregtech.common.gui.modularui.util; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; + +import org.lwjgl.input.Keyboard; + +import com.cleanroommc.modularui.api.widget.IGuiAction.MousePressed; +import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.utils.item.IItemHandler; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.widgets.slot.ItemSlot; +import com.cleanroommc.modularui.widgets.slot.ModularSlot; +import com.gtnewhorizon.gtnhlib.util.ItemUtil; + +import appeng.api.storage.data.IAEItemStack; +import fox.spiteful.avaritia.items.ItemMatterCluster; +import gregtech.api.util.GTUtility; +import gregtech.common.inventory.AEInventory; + +public class AEItemSlot extends ItemSlot { + + private final AEInventory inv; + private final int slot; + private boolean dumpable; + + public AEItemSlot(PanelSyncManager syncManager, String slotGroup, AEInventory inv, int slot) { + this.inv = inv; + this.slot = slot; + + slot(new AEModularSlot(inv, slot).slotGroup(slotGroup)); + + itemTooltip().tooltipBuilder(tooltip -> { + IAEItemStack stack = inv.getAEStackInSlot(slot); + + if (stack != null) { + tooltip.add( + GTUtility.translate("GT5U.gui.text.amount_out_of", stack.getStackSize(), inv.getAESlotLimit(slot))); + tooltip.newLine(); + if (dumpable) { + tooltip.add(EnumChatFormatting.BLUE + "Hold ALT and click slot to eject it into a matter cluster"); + } + } + }); + + syncManager.registerSyncedAction(slotGroup + "." + slot + ".dump", packet -> { + if (!dumpable) return; + + EntityPlayer player = syncManager.getContainer() + .getPlayer(); + + if (player.worldObj.isRemote) return; + + ItemStack split = inv.extractItem(slot, Integer.MAX_VALUE, false, true); + + if (ItemUtil.isStackEmpty(split)) return; + + ItemStack cluster = ItemMatterCluster.makeCluster(split); + + player.inventory.addItemStackToInventory(cluster); + + if (cluster.stackSize > 0) { + player.worldObj.spawnEntityInWorld( + new EntityItem(player.worldObj, player.posX + 0.5, player.posY + 0.5, player.posZ + 0.5, cluster)); + } + }); + + listenGuiAction((MousePressed) mouseButton -> { + if (!dumpable) return false; + + if (AEItemSlot.this.isHovering() && Keyboard.isKeyDown(Keyboard.KEY_LMENU)) { + syncManager.callSyncedAction(slotGroup + "." + slot + ".dump", buffer -> {}); + + return true; + } + + return false; + }); + } + + public AEItemSlot setDumpable(boolean dumpable) { + this.dumpable = dumpable; + return this; + } + + @Override + protected void drawSlotAmountText(int amount, String format) { + IAEItemStack stack = inv.getAEStackInSlot(slot); + GuiDraw.drawStandardSlotAmountText(stack == null ? 0L : stack.getStackSize(), format, getArea()); + } + + private static class AEModularSlot extends ModularSlot { + + public AEModularSlot(IItemHandler itemHandler, int index) { + super(itemHandler, index); + accessibility(false, false); + } + + @Override + public void putStack(ItemStack stack) { + // no-op to disable MC's slot syncing, which truncates >int max stack sizes + } + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/util/FilterSlot.java b/src/main/java/gregtech/common/gui/modularui/util/FilterSlot.java new file mode 100644 index 00000000000..55fdb7bfbf0 --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/util/FilterSlot.java @@ -0,0 +1,37 @@ +package gregtech.common.gui.modularui.util; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import net.minecraft.item.ItemStack; + +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.drawable.GuiTextures; +import com.cleanroommc.modularui.utils.item.IItemHandlerModifiable; +import com.cleanroommc.modularui.widgets.slot.ModularSlot; +import com.cleanroommc.modularui.widgets.slot.PhantomItemSlot; + +import gregtech.api.modularui2.GTGuiTextures; +import gregtech.api.util.item.PhantomSingleSlotItemStackHandler; + +public class FilterSlot extends PhantomItemSlot { + + public FilterSlot() { + itemTooltip().tooltipBuilder(tooltip -> tooltip.add(IKey.lang("GT5U.bus.filterTooltip.full"))); + tooltip(tooltip -> tooltip.add(IKey.lang("GT5U.bus.filterTooltip.empty"))); + background(GuiTextures.SLOT_ITEM, GTGuiTextures.OVERLAY_SLOT_FILTER); + } + + public FilterSlot(ModularSlot slot) { + this(); + slot(slot); + } + + public FilterSlot(IItemHandlerModifiable handler, int index) { + this(new ModularSlot(handler, index)); + } + + public FilterSlot(Supplier getter, Consumer setter) { + this(new PhantomSingleSlotItemStackHandler(getter, setter), 0); + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/util/ProxiedItemHandlerModifiable.java b/src/main/java/gregtech/common/gui/modularui/util/ProxiedItemHandlerModifiable.java new file mode 100644 index 00000000000..e5abfc7aadb --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/util/ProxiedItemHandlerModifiable.java @@ -0,0 +1,46 @@ +package gregtech.common.gui.modularui.util; + +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.Nullable; + +import com.cleanroommc.modularui.utils.item.IItemHandlerModifiable; + +public class ProxiedItemHandlerModifiable implements IItemHandlerModifiable { + + public final IItemHandlerModifiable proxied; + + public ProxiedItemHandlerModifiable(IItemHandlerModifiable proxied) { + this.proxied = proxied; + } + + @Override + public void setStackInSlot(int slot, @Nullable ItemStack stack) { + proxied.setStackInSlot(slot, stack); + } + + @Override + public int getSlots() { + return proxied.getSlots(); + } + + @Override + public @Nullable ItemStack getStackInSlot(int slot) { + return proxied.getStackInSlot(slot); + } + + @Override + public @Nullable ItemStack insertItem(int slot, @Nullable ItemStack stack, boolean simulate) { + return proxied.insertItem(slot, stack, simulate); + } + + @Override + public @Nullable ItemStack extractItem(int slot, int amount, boolean simulate) { + return proxied.extractItem(slot, amount, simulate); + } + + @Override + public int getSlotLimit(int slot) { + return proxied.getSlotLimit(slot); + } +} diff --git a/src/main/java/gregtech/common/gui/modularui/widget/IAEItemHandlerModifiable.java b/src/main/java/gregtech/common/gui/modularui/widget/IAEItemHandlerModifiable.java new file mode 100644 index 00000000000..9def3f70428 --- /dev/null +++ b/src/main/java/gregtech/common/gui/modularui/widget/IAEItemHandlerModifiable.java @@ -0,0 +1,103 @@ +package gregtech.common.gui.modularui.widget; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nullable; + +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +import com.cleanroommc.modularui.utils.item.IItemHandlerModifiable; +import com.gtnewhorizon.gtnhlib.item.ImmutableItemStack; +import com.gtnewhorizon.gtnhlib.item.InsertionItemStack; + +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import gregtech.api.util.GTUtility; +import gregtech.common.inventory.IAEInventory; + +/** + * A version of {@link IItemHandlerModifiable} that supports AE stacks (stacks bigger than int max). + * By default all MC stack operations proxy to the AE method equivalents and truncate any stack sizes >int max. + */ +public interface IAEItemHandlerModifiable extends IItemHandlerModifiable, IAEInventory { + + IAEItemStack getAEStackInSlot(int slot); + + @Override + default ItemStack getStackInSlot(int slot) { + IAEItemStack stack = getAEStackInSlot(slot); + + return stack == null ? null : stack.getItemStack(); + } + + @Nullable + IAEItemStack insertAEItem(int slot, @NotNull IAEItemStack stack, boolean simulate, boolean forced); + + default int insertItem(int slot, @Nullable ImmutableItemStack stack, boolean simulate, boolean forced) { + if (stack == null || stack.isEmpty()) return 0; + + IAEItemStack rejected = insertAEItem(slot, AEItemStack.create(stack.toStack()), simulate, forced); + + return rejected == null ? 0 : (int) rejected.getStackSize(); + } + + @Override + default ItemStack insertItem(int slot, @Nullable ItemStack stack, boolean simulate) { + if (stack == null) return null; + + InsertionItemStack insertion = new InsertionItemStack(stack); + + insertion.set(insertItem(slot, insertion, simulate, false)); + + return insertion.isEmpty() ? null : insertion.toStack(); + } + + @Nullable + IAEItemStack extractAEItem(int slot, long amount, boolean simulate, boolean forced); + + default ItemStack extractItem(int slot, int amount, boolean simulate, boolean forced) { + IAEItemStack stack = extractAEItem(slot, amount, simulate, forced); + + return stack == null ? null : stack.getItemStack(); + } + + @Override + @Nullable + default ItemStack extractItem(int slot, int amount, boolean simulate) { + return extractItem(slot, amount, simulate, false); + } + + default long getAESlotLimit(int slot) { + return getAESlotLimit(slot, getAEStackInSlot(slot)); + } + + long getAESlotLimit(int slot, IAEItemStack stack); + + @Override + default int getSlotLimit(int slot) { + return GTUtility.longToInt(getAESlotLimit(slot)); + } + + @Override + default boolean isItemValid(int slot, ItemStack stack) { + return isAEItemValid(slot, AEItemStack.create(stack)); + } + + default List getAEStacks() { + List ret = new ArrayList<>(); + for (int i = 0; i < getSlots(); i++) { + ret.add(getAEStackInSlot(i)); + } + return ret; + } + + void setStackInSlot(int slot, IAEItemStack stack); + + @Override + default void setStackInSlot(int slot, ItemStack stack) { + setStackInSlot(slot, AEItemStack.create(stack)); + } +} diff --git a/src/main/java/gregtech/common/inventory/AEInventory.java b/src/main/java/gregtech/common/inventory/AEInventory.java new file mode 100644 index 00000000000..eef0fe9e748 --- /dev/null +++ b/src/main/java/gregtech/common/inventory/AEInventory.java @@ -0,0 +1,473 @@ +package gregtech.common.inventory; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.IntStream; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.cleanroommc.modularui.utils.item.INBTSerializable; + +import appeng.api.config.AccessRestriction; +import appeng.api.config.Actionable; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.IMEMonitorHandlerReceiver; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.util.item.AEItemStack; +import appeng.util.item.ItemList; +import gregtech.api.util.GTDataUtils; +import gregtech.api.util.GTUtility; +import gregtech.common.gui.modularui.widget.IAEItemHandlerModifiable; + +/** + * An inventory that stores AE item stacks. This also sends monitor updates as needed. + */ +public abstract class AEInventory + implements IAEInventory, IMEMonitor, IAEItemHandlerModifiable, INBTSerializable { + + private final Map, Object> listeners = new HashMap<>(); + + public final int slotCount; + public final IAEItemStack[] inventory; + + protected final int[] allSlots; + + public AEInventory(IAEItemStack[] inventory) { + this.inventory = inventory; + slotCount = inventory.length; + allSlots = IntStream.range(0, slotCount) + .toArray(); + } + + public AEInventory(int slotCount) { + this.inventory = new IAEItemStack[slotCount]; + this.slotCount = slotCount; + allSlots = IntStream.range(0, slotCount) + .toArray(); + } + + @Override + public IItemList getStorageList() { + ItemList list = new ItemList(); + + for (IAEItemStack stack : inventory) { + if (stack != null) list.add(stack.copy()); + } + + return list; + } + + @Override + public IAEItemStack getAvailableItem(@NotNull IAEItemStack request, int iteration) { + IAEItemStack result = request.empty(); + + for (IAEItemStack stack : inventory) { + if (stack != null && stack.isSameType(request)) { + result.incStackSize(stack.getStackSize()); + } + } + + return result; + } + + @Override + public IItemList getAvailableItems(IItemList out, int iteration) { + for (IAEItemStack stack : inventory) { + if (stack != null) out.add(stack.copy()); + } + + return out; + } + + @Override + public void addListener(IMEMonitorHandlerReceiver l, Object verificationToken) { + // noinspection unchecked + listeners.put(l, verificationToken); + } + + @Override + public void removeListener(IMEMonitorHandlerReceiver l) { + listeners.remove(l); + } + + @Override + public AccessRestriction getAccess() { + return AccessRestriction.READ_WRITE; + } + + @Override + public boolean isPrioritized(IAEItemStack input) { + return false; + } + + @Override + public boolean canAccept(IAEItemStack input) { + return true; + } + + @Override + public int getPriority() { + return 0; + } + + @Override + public int getSlot() { + return 0; + } + + @Override + public boolean validForPass(int i) { + return false; + } + + protected int[] getValidInjectionSlots(IAEItemStack input) { + return allSlots; + } + + protected int[] getValidExtractionSlots(IAEItemStack request) { + return allSlots; + } + + protected boolean allowPullStack(int slotIndex) { + return true; + } + + protected boolean allowPutStack(int slotIndex, IAEItemStack toInsert) { + return true; + } + + @Override + public IAEItemStack injectItems(IAEItemStack input, Actionable mode, BaseActionSource src) { + return injectItems(input, mode, src, getValidInjectionSlots(input)); + } + + public @Nullable IAEItemStack injectItems(IAEItemStack input, Actionable mode, BaseActionSource src, int[] slots) { + IAEItemStack inserted = null; + + input = input.copy(); + + // First pass: try to find slots that have the item already + for (int slotIndex : slots) { + if (input.getStackSize() <= 0) break; + + if (!allowPutStack(slotIndex, input)) continue; + + IAEItemStack slot = inventory[slotIndex]; + + if (slot == null) continue; + if (!input.isSameType(slot)) continue; + + long maxStack = getAESlotLimit(slotIndex, slot); + + long toTransfer = Math.min(maxStack - slot.getStackSize(), input.getStackSize()); + + if (toTransfer > 0) { + input.decStackSize(toTransfer); + if (mode == Actionable.MODULATE) slot.incStackSize(toTransfer); + + if (inserted == null) { + inserted = input.empty(); + } + + inserted.incStackSize(toTransfer); + } + } + + // Second pass: try to find any empty slot + for (int slotIndex : slots) { + if (input.getStackSize() <= 0) break; + + if (!allowPutStack(slotIndex, input)) continue; + + IAEItemStack slot = inventory[slotIndex]; + + if (slot != null) continue; + + slot = input.empty(); + + if (mode == Actionable.MODULATE) inventory[slotIndex] = slot; + + long maxStack = getAESlotLimit(slotIndex, slot); + + long toTransfer = Math.min(maxStack - slot.getStackSize(), input.getStackSize()); + + if (toTransfer > 0) { + input.decStackSize(toTransfer); + if (mode == Actionable.MODULATE) slot.incStackSize(toTransfer); + + if (inserted == null) { + inserted = input.empty(); + } + + inserted.incStackSize(toTransfer); + } + } + + if (inserted != null && mode == Actionable.MODULATE) { + postChange(src, inserted); + } + + return input.getStackSize() == 0 ? null : input; + } + + private void postChange(BaseActionSource src, IAEItemStack inserted) { + Iterable changes = GTDataUtils.singletonIterable(inserted); + + listeners.forEach((handler, o) -> { + if (handler.isValid(o)) { + handler.postChange(this, changes, src); + } + }); + } + + @Override + public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src) { + return extractItems(request, mode, src, getValidExtractionSlots(request)); + } + + private @Nullable IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src, + int[] slots) { + IAEItemStack extracted = null; + + for (int slotIndex : slots) { + if (!allowPullStack(slotIndex)) continue; + + IAEItemStack slot = inventory[slotIndex]; + + if (slot == null || !request.isSameType(slot)) continue; + + long toConsume = Math.min(slot.getStackSize(), request.getStackSize()); + + if (mode == Actionable.MODULATE) { + slot.decStackSize(toConsume); + + if (slot.getStackSize() <= 0) { + inventory[slotIndex] = null; + } + } + + if (extracted == null) { + extracted = slot.empty(); + } + + extracted.incStackSize(toConsume); + } + + if (extracted != null && mode == Actionable.MODULATE) { + postChange( + src, + extracted.empty() + .setStackSize(-extracted.getStackSize())); + } + + return extracted; + } + + @Override + public StorageChannel getChannel() { + return StorageChannel.ITEMS; + } + + @Override + public int getSlots() { + return slotCount; + } + + @Override + public @Nullable IAEItemStack getAEStackInSlot(int slot) { + return GTDataUtils.getIndexSafe(inventory, slot); + } + + public int indexOf(ItemStack stack) { + for (int i = 0; i < inventory.length; i++) { + IAEItemStack slot = inventory[i]; + + if (slot != null && slot.isSameType(stack)) return i; + } + + return -1; + } + + public int indexOf(Predicate filter) { + for (int i = 0; i < inventory.length; i++) { + if (filter.test(inventory[i])) return i; + } + + return -1; + } + + @Override + public @Nullable IAEItemStack insertAEItem(int slot, @NotNull IAEItemStack stack, boolean simulate, + boolean forced) { + if (slot < 0 || slot >= slotCount) return stack; + if (!forced && !allowPutStack(slot, stack)) return stack; + + IAEItemStack existing = inventory[slot]; + + if (existing == null) { + existing = stack.empty(); + } + + if (simulate) { + existing = existing.copy(); + } + + if (existing.isSameType(stack)) { + long maxStorable = forced ? Long.MAX_VALUE : getAESlotLimit(slot, existing); + + long toTransfer = Math.min(maxStorable - existing.getStackSize(), stack.getStackSize()); + + if (toTransfer > 0) { + existing.incStackSize(toTransfer); + stack.decStackSize(toTransfer); + + if (!simulate) { + inventory[slot] = existing; + + postChange( + getActionSource(), + existing.empty() + .setStackSize(toTransfer)); + } + } + } + + return stack.getStackSize() > 0 ? stack : null; + } + + @Override + public @Nullable IAEItemStack extractAEItem(int slot, long amount, boolean simulate, boolean forced) { + if (slot < 0 || slot >= slotCount) return null; + if (!forced && !allowPullStack(slot)) return null; + + IAEItemStack existing = inventory[slot]; + + if (existing == null) return null; + + long toExtract = Math.min(existing.getStackSize(), amount); + + IAEItemStack extracted = existing.empty() + .setStackSize(toExtract); + + if (!simulate) { + existing.decStackSize(toExtract); + + if (existing.getStackSize() <= 0) { + inventory[slot] = null; + } + + postChange( + getActionSource(), + existing.empty() + .setStackSize(-toExtract)); + } + + return extracted; + } + + @Override + public long getAESlotLimit(int slot, @Nullable IAEItemStack stack) { + return Long.MAX_VALUE; + } + + @Override + public void setStackInSlot(int slot, @Nullable IAEItemStack stack) { + if (slot < 0 || slot >= slotCount) return; + + IAEItemStack existing = inventory[slot]; + + inventory[slot] = stack != null ? stack.copy() : null; + + if (existing != null && !existing.isSameType(stack)) { + postChange( + getActionSource(), + existing.empty() + .setStackSize(-existing.getStackSize())); + existing = null; + } + + if (stack != null) { + long previousAmount = existing == null ? 0 : existing.getStackSize(); + + long delta = stack.getStackSize() - previousAmount; + + postChange( + getActionSource(), + stack.empty() + .setStackSize(delta)); + } + } + + @Override + public NBTTagCompound serializeNBT() { + return writeToNBT(new NBTTagCompound()); + } + + public NBTTagCompound writeToNBT(NBTTagCompound tag) { + NBTTagList inv = new NBTTagList(); + tag.setTag("inv", inv); + + for (int i = 0; i < inventory.length; i++) { + IAEItemStack stack = inventory[i]; + + if (stack == null) continue; + + NBTTagCompound item = new NBTTagCompound(); + + stack.writeToNBT(item); + + item.setInteger("index", i); + + inv.appendTag(item); + } + + return tag; + } + + @Override + public void deserializeNBT(NBTTagCompound nbt) { + readFromNBT(nbt); + } + + public void readFromNBT(NBTTagCompound tag) { + Arrays.fill(inventory, null); + + for (NBTTagCompound item : GTUtility.getCompoundTagList(tag, "inv")) { + int index = item.getInteger("index"); + + if (index < 0 || index >= slotCount) continue; + + inventory[index] = AEItemStack.loadItemStackFromNBT(item); + } + } + + protected abstract AEInventory copyImpl(); + + public AEInventory copy() { + AEInventory copy = copyImpl(); + + for (int i = 0; i < inventory.length; i++) { + IAEItemStack stack = inventory[i]; + + copy.inventory[i] = stack == null ? null : stack.copy(); + } + + return copy; + } + + public abstract BaseActionSource getActionSource(); + + public AEInventoryItemIO getItemIO() { + return new AEInventoryItemIO(this); + } +} diff --git a/src/main/java/gregtech/common/inventory/AEInventoryItemIO.java b/src/main/java/gregtech/common/inventory/AEInventoryItemIO.java new file mode 100644 index 00000000000..5d91cd52949 --- /dev/null +++ b/src/main/java/gregtech/common/inventory/AEInventoryItemIO.java @@ -0,0 +1,42 @@ +package gregtech.common.inventory; + +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.gtnhlib.item.AbstractInventoryIterator; +import com.gtnewhorizon.gtnhlib.item.ImmutableItemStack; +import com.gtnewhorizon.gtnhlib.item.InventoryIterator; +import com.gtnewhorizon.gtnhlib.item.SimpleItemIO; + +public class AEInventoryItemIO extends SimpleItemIO { + + private final AEInventory inventory; + + public AEInventoryItemIO(AEInventory inventory) { + this.inventory = inventory; + } + + @Override + protected @NotNull InventoryIterator iterator(int[] allowedSlots) { + return new AbstractInventoryIterator(inventory.allSlots, allowedSlots) { + + @Override + protected ItemStack getStackInSlot(int slot) { + return inventory.getStackInSlot(slot); + } + + @Override + public ItemStack extract(int amount, boolean forced) { + return inventory.extractItem(getCurrentSlot(), amount, false); + } + + @Override + public int insert(ImmutableItemStack stack, boolean forced) { + if (stack.isEmpty()) return 0; + + return inventory.insertItem(getCurrentSlot(), stack, false, forced); + } + }; + } +} diff --git a/src/main/java/gregtech/common/inventory/IAEInventory.java b/src/main/java/gregtech/common/inventory/IAEInventory.java new file mode 100644 index 00000000000..ea2c1758fee --- /dev/null +++ b/src/main/java/gregtech/common/inventory/IAEInventory.java @@ -0,0 +1,28 @@ +package gregtech.common.inventory; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import appeng.api.storage.data.IAEItemStack; + +public interface IAEInventory { + + int getSlots(); + + @Nullable + IAEItemStack getAEStackInSlot(int slot); + + @Nullable + IAEItemStack insertAEItem(int slot, @NotNull IAEItemStack stack, boolean simulate, boolean forced); + + @Nullable + IAEItemStack extractAEItem(int slot, long amount, boolean simulate, boolean forced); + + default boolean isAEItemValid(int slot, @NotNull IAEItemStack stack) { + return true; + } + + long getAESlotLimit(int slot, @Nullable IAEItemStack stack); + + void setStackInSlot(int slot, @Nullable IAEItemStack stack); +} diff --git a/src/main/java/gregtech/common/misc/GTMiscCommand.java b/src/main/java/gregtech/common/misc/GTMiscCommand.java index ed0580ccab2..efe8282b53a 100644 --- a/src/main/java/gregtech/common/misc/GTMiscCommand.java +++ b/src/main/java/gregtech/common/misc/GTMiscCommand.java @@ -6,6 +6,7 @@ import static gregtech.common.misc.WirelessNetworkManager.setUserEU; import java.lang.reflect.Field; +import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @@ -251,19 +252,35 @@ private void processPollutionCommand(ICommandSender sender, String[] args) { amount); } + private static BigInteger parseEU(String eu) { + if (eu.contains("e")) { + String[] halves = eu.split("e"); + + double scalar = Double.parseDouble(halves[0]); + int exponent = Integer.parseInt(halves[1]); + + return BigDecimal.valueOf(scalar) + .multiply( + BigDecimal.valueOf(10) + .pow(exponent)) + .toBigInteger(); + } else { + return new BigInteger(eu); + } + } + private void processGlobalEnergyAddCommand(ICommandSender sender, String[] args) { String username = args[1]; String formatted_username = EnumChatFormatting.BLUE + username + EnumChatFormatting.RESET; UUID uuid = SpaceProjectManager.getPlayerUUIDFromName(username); - String EU_String = args[2]; + BigInteger eu = parseEU(args[2]); // Usage is /gt global_energy_add username EU - String EU_string_formatted = EnumChatFormatting.RED + formatNumber(new BigInteger(EU_String)) - + EnumChatFormatting.RESET; + String EU_string_formatted = EnumChatFormatting.RED + formatNumber(eu) + EnumChatFormatting.RESET; - if (addEUToGlobalEnergyMap(uuid, new BigInteger(EU_String))) { + if (addEUToGlobalEnergyMap(uuid, eu)) { sendChatToPlayer( sender, "Successfully added " + EU_string_formatted @@ -295,21 +312,21 @@ private void processGlobalEnergySetCommand(ICommandSender sender, String[] args) String formatted_username = EnumChatFormatting.BLUE + username + EnumChatFormatting.RESET; UUID uuid = SpaceProjectManager.getPlayerUUIDFromName(username); - String EU_String_0 = args[2]; + BigInteger eu = parseEU(args[2]); - if ((new BigInteger(EU_String_0).compareTo(BigInteger.ZERO)) < 0) { + if ((eu.compareTo(BigInteger.ZERO)) < 0) { sendChatToPlayer(sender, "Cannot set a users energy network to a negative value."); return; } - setUserEU(uuid, new BigInteger(EU_String_0)); + setUserEU(uuid, eu); sendChatToPlayer( sender, "Successfully set " + formatted_username + "'s global energy network to " + EnumChatFormatting.RED - + formatNumber(new BigInteger(EU_String_0)) + + formatNumber(eu) + EnumChatFormatting.RESET + "EU."); } diff --git a/src/main/java/gregtech/common/modularui2/factory/SelectItemGuiBuilder.java b/src/main/java/gregtech/common/modularui2/factory/SelectItemGuiBuilder.java index 236947befa2..7a7f7f0e8cd 100644 --- a/src/main/java/gregtech/common/modularui2/factory/SelectItemGuiBuilder.java +++ b/src/main/java/gregtech/common/modularui2/factory/SelectItemGuiBuilder.java @@ -175,7 +175,7 @@ public ModularPanel build() { .height(18) .top(22)); panel.child( - new SlotLikeButtonWidget(() -> selected > -1 ? choices.get(selected) : null) + new SlotLikeButtonWidget(() -> selected > DESELECTED ? choices.get(selected) : null) .background( GTGuiTextures.SLOT_ITEM_DARK, new DynamicDrawable( diff --git a/src/main/java/gregtech/common/tileentities/storage/MTEDigitalChestBase.java b/src/main/java/gregtech/common/tileentities/storage/MTEDigitalChestBase.java index 2ae7dece916..24e0694de94 100644 --- a/src/main/java/gregtech/common/tileentities/storage/MTEDigitalChestBase.java +++ b/src/main/java/gregtech/common/tileentities/storage/MTEDigitalChestBase.java @@ -627,7 +627,7 @@ public int insert(ImmutableItemStack stack, boolean forced) { int insertable = Math.min((forced ? Integer.MAX_VALUE : getItemCapacity()) - getItemCount(), remaining); if (!simulated) { - if (ItemUtil.isStackEmpty(getItemStack())) { + if (getItemCount() <= 0) { setItemStack(stack.toStack(0)); } diff --git a/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java b/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java index 5ef5a38c02a..21d96dd028b 100644 --- a/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java +++ b/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java @@ -50,6 +50,7 @@ import gregtech.api.enums.ItemList; import gregtech.api.enums.MachineType; import gregtech.api.enums.SoundResource; +import gregtech.api.enums.VoltageIndex; import gregtech.api.metatileentity.implementations.MTEBasicBatteryBuffer; import gregtech.api.metatileentity.implementations.MTEBasicHull; import gregtech.api.metatileentity.implementations.MTEBasicMachineWithRecipe; @@ -61,6 +62,7 @@ import gregtech.api.metatileentity.implementations.MTEHatchEnergyDebug; import gregtech.api.metatileentity.implementations.MTEHatchInput; import gregtech.api.metatileentity.implementations.MTEHatchInputBus; +import gregtech.api.metatileentity.implementations.MTEHatchInputBusCompressed; import gregtech.api.metatileentity.implementations.MTEHatchInputBusDebug; import gregtech.api.metatileentity.implementations.MTEHatchInputDebug; import gregtech.api.metatileentity.implementations.MTEHatchMagnet; @@ -70,6 +72,7 @@ import gregtech.api.metatileentity.implementations.MTEHatchNanite; import gregtech.api.metatileentity.implementations.MTEHatchOutput; import gregtech.api.metatileentity.implementations.MTEHatchOutputBus; +import gregtech.api.metatileentity.implementations.MTEHatchOutputBusCompressed; import gregtech.api.metatileentity.implementations.MTEHatchQuadrupleHumongous; import gregtech.api.metatileentity.implementations.MTEHatchVoid; import gregtech.api.metatileentity.implementations.MTEHatchVoidBus; @@ -9006,6 +9009,136 @@ private static void registerCokeOvenHatch() { .set(new MTEHatchCokeOven(COKE_OVEN_HATCH.ID, "hatch.cokeoven", "Coke Oven Hatch").getStackForm(1L)); } + private static void registerCompressedBus() { + ItemList.CompressedOutputBusLuV.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_COMPRESSED_1.ID, + "hatch.comp-output-bus.tier.00", + "Compressed Output Bus (LuV)", + VoltageIndex.LuV, + 256).getStackForm(1)); + + ItemList.CompressedOutputBusZPM.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_COMPRESSED_2.ID, + "hatch.comp-output-bus.tier.01", + "Compressed Output Bus (ZPM)", + VoltageIndex.ZPM, + 2048).getStackForm(1)); + + ItemList.CompressedOutputBusUV.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_COMPRESSED_3.ID, + "hatch.comp-output-bus.tier.02", + "Compressed Output Bus (UV)", + VoltageIndex.UV, + 16384).getStackForm(1)); + + ItemList.CompressedOutputBusUHV.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_COMPRESSED_4.ID, + "hatch.comp-output-bus.tier.03", + "Compressed Output Bus (UHV)", + VoltageIndex.UHV, + 131072).getStackForm(1)); + + ItemList.CompressedOutputBusUEV.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_QUANTUM_1.ID, + "hatch.quantum-output-bus.tier.00", + "Quantum Output Bus (UEV)", + VoltageIndex.UEV, + 2097152).getStackForm(1)); + + ItemList.CompressedOutputBusUIV.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_QUANTUM_2.ID, + "hatch.quantum-output-bus.tier.01", + "Quantum Output Bus (UIV)", + VoltageIndex.UIV, + Integer.MAX_VALUE / 64L).getStackForm(1)); + + ItemList.CompressedOutputBusUMV.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_QUANTUM_3.ID, + "hatch.quantum-output-bus.tier.02", + "Quantum Output Bus (UMV)", + VoltageIndex.UMV, + Integer.MAX_VALUE * 64L).getStackForm(1)); + + ItemList.CompressedOutputBusUXV.set( + new MTEHatchOutputBusCompressed( + HATCH_OUTPUT_BUS_QUANTUM_4.ID, + "hatch.quantum-output-bus.tier.03", + "Quantum Output Bus (UXV)", + VoltageIndex.UXV, + Long.MAX_VALUE / 64L).getStackForm(1)); + + ItemList.CompressedInputBusLuV.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_COMPRESSED_1.ID, + "hatch.comp-input-bus.tier.00", + "Compressed Input Bus (LuV)", + VoltageIndex.LuV, + 256).getStackForm(1)); + + ItemList.CompressedInputBusZPM.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_COMPRESSED_2.ID, + "hatch.comp-input-bus.tier.01", + "Compressed Input Bus (ZPM)", + VoltageIndex.ZPM, + 2048).getStackForm(1)); + + ItemList.CompressedInputBusUV.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_COMPRESSED_3.ID, + "hatch.comp-input-bus.tier.02", + "Compressed Input Bus (UV)", + VoltageIndex.UV, + 16384).getStackForm(1)); + + ItemList.CompressedInputBusUHV.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_COMPRESSED_4.ID, + "hatch.comp-input-bus.tier.03", + "Compressed Input Bus (UHV)", + VoltageIndex.UHV, + 131072).getStackForm(1)); + + ItemList.CompressedInputBusUEV.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_QUANTUM_1.ID, + "hatch.quantum-input-bus.tier.00", + "Quantum Input Bus (UEV)", + VoltageIndex.UEV, + 2097152).getStackForm(1)); + + ItemList.CompressedInputBusUIV.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_QUANTUM_2.ID, + "hatch.quantum-input-bus.tier.01", + "Quantum Input Bus (UIV)", + VoltageIndex.UIV, + Integer.MAX_VALUE / 64L).getStackForm(1)); + + ItemList.CompressedInputBusUMV.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_QUANTUM_3.ID, + "hatch.quantum-input-bus.tier.02", + "Quantum Input Bus (UMV)", + VoltageIndex.UMV, + Integer.MAX_VALUE * 64L).getStackForm(1)); + + ItemList.CompressedInputBusUXV.set( + new MTEHatchInputBusCompressed( + HATCH_INPUT_BUS_QUANTUM_4.ID, + "hatch.quantum-input-bus.tier.03", + "Quantum Input Bus (UXV)", + VoltageIndex.UXV, + Long.MAX_VALUE / 64L).getStackForm(1)); + } + private static void registerQuantumTank() { ItemList.Quantum_Tank_LV .set(new MTEQuantumTank(QUANTUM_TANK_LV.ID, "quantum.tank.tier.06", "Quantum Tank I", 6).getStackForm(1L)); @@ -10668,6 +10801,7 @@ public void run() { registerOutputBus(); registerVoidBus(); registerCokeOvenHatch(); + registerCompressedBus(); registerMufflerHatch(); registerBoiler(); registerBatteryBuffer1x1(); diff --git a/src/main/java/kekztech/common/CommonProxy.java b/src/main/java/kekztech/common/CommonProxy.java index 1baa4e5c691..c504ffd50f7 100644 --- a/src/main/java/kekztech/common/CommonProxy.java +++ b/src/main/java/kekztech/common/CommonProxy.java @@ -4,6 +4,8 @@ import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import gregtech.api.enums.Mods; +import gregtech.api.metatileentity.implementations.MTEHatchInputBusCompressed; +import gregtech.api.metatileentity.implementations.MTEHatchOutputBusCompressed; import kekztech.Items; import kekztech.common.items.ErrorItem; import kekztech.common.items.MetaItemCraftingComponent; @@ -42,5 +44,7 @@ public void postInit(final FMLPostInitializationEvent e) { } MTEHatchTFFT.registerAEIntegration(); + MTEHatchOutputBusCompressed.registerAEIntegration(); + MTEHatchInputBusCompressed.registerAEIntegration(); } } diff --git a/src/main/java/tectech/thing/metaTileEntity/multi/MTEEyeOfHarmony.java b/src/main/java/tectech/thing/metaTileEntity/multi/MTEEyeOfHarmony.java index 005ef966889..45a7c251282 100644 --- a/src/main/java/tectech/thing/metaTileEntity/multi/MTEEyeOfHarmony.java +++ b/src/main/java/tectech/thing/metaTileEntity/multi/MTEEyeOfHarmony.java @@ -72,11 +72,11 @@ import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.util.GTLanguageManager; import gregtech.api.util.GTUtility; +import gregtech.api.util.ItemEjectionHelper; import gregtech.api.util.MultiblockTooltipBuilder; import gregtech.api.util.shutdown.ShutDownReason; import gregtech.common.misc.GTStructureChannels; import gregtech.common.tileentities.machines.MTEHatchInputBusME; -import gregtech.common.tileentities.machines.outputme.MTEHatchOutputBusME; import gregtech.common.tileentities.machines.outputme.MTEHatchOutputME; import gtPlusPlus.core.util.minecraft.ItemUtils; import gtneioreplugin.plugin.block.BlockDimensionDisplay; @@ -875,26 +875,14 @@ public boolean checkMachine_EM(IGregTechTileEntity iGregTechTileEntity, ItemStac return false; } - // Check if there is 1 output bus, and it is a ME output bus. - { - if (mOutputBusses.size() != 1) { - return false; - } - - if (!(mOutputBusses.get(0) instanceof MTEHatchOutputBusME)) { - return false; - } + // Check if there are output busses + if (mOutputBusses.isEmpty()) { + return false; } - // Check if there is 1 output hatch, and they are ME output hatches. - { - if (mOutputHatches.size() != 1) { - return false; - } - - if (!(mOutputHatches.get(0) instanceof MTEHatchOutputME)) { - return false; - } + // Check if there is 1 output hatch + if (mOutputHatches.size() != 1) { + return false; } // Check there is 1 input bus, and it is not a stocking input bus. @@ -1546,17 +1534,15 @@ public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { private void outputItemToAENetwork(ItemStack item, long amount) { if (item == null || amount <= 0) return; - while (amount >= Integer.MAX_VALUE) { - ItemStack tmpItem = item.copy(); - tmpItem.stackSize = Integer.MAX_VALUE; - mOutputBusses.get(0) - .storePartial(tmpItem); - amount -= Integer.MAX_VALUE; + ItemEjectionHelper ejectionHelper = new ItemEjectionHelper(this); + + for (long i = 0; i < amount; i += Integer.MAX_VALUE) { + int xfer = (int) Math.min(amount - i, Integer.MAX_VALUE); + + ejectionHelper.ejectStack(GTUtility.copyAmountUnsafe(xfer, item)); } - ItemStack tmpItem = item.copy(); - tmpItem.stackSize = (int) amount; - mOutputBusses.get(0) - .storePartial(tmpItem); + + ejectionHelper.commit(); } private void outputFluidToAENetwork(FluidStack fluid, long amount) { diff --git a/src/main/resources/assets/gregtech/lang/en_US.lang b/src/main/resources/assets/gregtech/lang/en_US.lang index bc357bf72a9..6670f54bc37 100644 --- a/src/main/resources/assets/gregtech/lang/en_US.lang +++ b/src/main/resources/assets/gregtech/lang/en_US.lang @@ -1432,6 +1432,7 @@ GT5U.gui.button.power_panel=Open Power Panel GT5U.gui.button.turbinemenu=Open Chamber Controller GT5U.gui.button.machineinfo=Display Machine Information GT5U.gui.button.max_parallel=Always use maximum +GT5U.gui.button.compressed_bus_settings=Open Bus Settings GT5U.gui.text.rangedvalue=Range: %s-%s GT5U.gui.text.lockedvalue=Locked: %s @@ -1573,6 +1574,10 @@ GT5U.gui.text.invalidfluidsup=Invalid Fluid Supplied GT5U.gui.text.amperage=Amperage GT5U.gui.text.voltagetier=Voltage Tier GT5U.gui.text.ticks_between_refill=Ticks Between Refills +GT5U.gui.text.stack_capacity=Stack Capacity +GT5U.gui.text.bus_settings=Bus Settings +GT5U.gui.text.amount_out_of=ยง9Amount: %,d / %,d +GT5U.gui.text.compressed_bus_stored_items=Hold SHIFT to show all stored items GT5U.gui.hoverable.runningfine=Running Fine.