From f5912ef2e3ff768d64ffa8d518f39fbc54f9759b Mon Sep 17 00:00:00 2001 From: Andrei Antropov Date: Fri, 27 Oct 2023 15:10:07 +0300 Subject: [PATCH] Add `LevelMaintainerTerminal` rework logic inside `TileLevelMaintainer` (#162) * Use new interface terminal API * Update dependencies.gradle * feat: Update core hooks and integrations * api: Add `LevelTerminalRegistry` functionality * feat: Use `customName` to display in `GuiFluidLevelEmitter` * feat: Rework scheduling and data storage in `TileLevelMaintainer` functionality * feat: Add new item `LevelTerminal` * feat: Support back navigation functionality * feat: add back navigation in `LevelMaintainer` from terminal * use `IGuiTooltipHandler` directly from ae2 include #160 * fix correct `InterfaceTerminalSupportedClassProvider` deprecation * Implement new version of `InterfaceWireless` based on `InterfaceTerminal` * Fix `LevelTerminal` data recursion and few in fixes gui * Use `aeRenderItem` directly and fix `zIndex` in custom slots * Fix rendering numbers bigger than 2.1G through `aeRenderItem` * Fix fails on `getCraftingItem` no root cause was found * Fix add packet logging and try to not fail after receive corrupted packet * Fix add logging around empty configuration * Fix packet corruption and log invalid data * Fix packet corruption with level emitters * Correct handle overwrite packet * Fix intercept dnd click from GT5 hook for `AppEngGuiHandler` keyword `net.bdew.neiaddons.appeng.AppEngGuiHandler` * update be+deps * Update dependencies.gradle * Update dependencies.gradle * Fix `zIndexes` for compatability with `DuraDisplay` * Update AE2 and fix compatability * Change `ForgeDirection` side serialization to `byte` * Fix tooltip zIndexes * Rename all rest parts related to `Level terminal` * Code cleanup after review * Remove duplicated dependency declaration --------- Co-authored-by: Firenoo <49818773+firenoo@users.noreply.github.com> Co-authored-by: Martin Robertz --- dependencies.gradle | 47 +- .../glodblock/github/api/FluidCraftAPI.java | 8 + .../glodblock/github/api/IFluidCraftAPI.java | 7 + .../java/com/glodblock/github/api/ISide.java | 8 + .../registries/ILevelTerminalRegistry.java | 20 + .../github/api/registries/ILevelViewable.java | 53 + .../api/registries/ILevelViewableAdapter.java | 8 + ...tingStatus.java => GuiCraftingStatus.java} | 44 +- .../github/client/gui/GuiDualInterface.java | 7 +- .../client/gui/GuiEssentiaTerminal.java | 11 +- .../github/client/gui/GuiFCImgButton.java | 11 + .../client/gui/GuiFluidCraftAmount.java | 23 +- .../client/gui/GuiFluidCraftConfirm.java | 23 +- .../github/client/gui/GuiFluidInterface.java | 4 +- .../client/gui/GuiFluidLevelEmitter.java | 5 +- .../client/gui/GuiFluidPatternEncoder.java | 11 +- .../github/client/gui/GuiFluidStorageBus.java | 4 +- .../github/client/gui/GuiFluidTerminal.java | 9 +- .../gui/GuiInterfaceTerminalWireless.java | 769 --------- .../client/gui/GuiInterfaceWireless.java | 1369 ++++++++++++++++ .../github/client/gui/GuiLevelMaintainer.java | 227 ++- .../github/client/gui/GuiLevelTerminal.java | 1408 +++++++++++++++++ .../github/client/gui/GuiLevelWireless.java | 24 + .../client/gui/GuiPatternValueAmount.java | 13 +- .../github/client/gui/GuiRenamer.java | 57 +- .../github/client/gui/base/FCBaseMEGui.java | 23 +- .../github/client/gui/base/FCGuiAmount.java | 10 +- .../client/gui/base/FCGuiEncodeTerminal.java | 10 +- .../container/ContainerFluidCraftConfirm.java | 4 + .../container/ContainerInterfaceWireless.java | 361 +---- .../container/ContainerLevelMaintainer.java | 111 +- .../gui/container/ContainerLevelTerminal.java | 406 +++++ .../gui/container/ContainerLevelWireless.java | 17 + .../client/textures/FCPartsTexture.java | 3 + .../com/glodblock/github/common/Config.java | 8 + .../common/item/ItemPartLevelTerminal.java | 71 + .../item/ItemWirelessLevelTerminal.java | 51 + .../item/ItemWirelessUltraTerminal.java | 13 + .../common/parts/PartFluidLevelEmitter.java | 5 +- .../common/parts/PartLevelTerminal.java | 83 + .../common/tile/TileLevelMaintainer.java | 557 ++++--- .../github/coremod/FCClassTransformer.java | 6 +- .../github/coremod/hooker/CoreModHooks.java | 9 +- .../coremod/hooker/CoreModHooksClient.java | 13 - .../registries/LevelTerminalRegistry.java | 71 + .../PartFluidLevelEmitterAdapter.java | 88 ++ .../adapters/PartLevelEmitterAdapter.java | 117 ++ ...EITransfermer.java => NEITransformer.java} | 6 +- .../PacketCompressedNBTTransformer.java | 61 - .../opencomputers/DriverLevelMaintainer.java | 2 +- .../crossmod/waila/TileWailaDataProvider.java | 4 +- ... => LevelMaintainerWailaDataProvider.java} | 12 +- .../github/inventory/gui/GuiType.java | 38 +- ...erminal.java => IClickableInTerminal.java} | 2 +- .../WirelessInterfaceTerminalInventory.java | 6 +- .../item/WirelessLevelTerminalInventory.java | 146 ++ .../github/loader/ChannelLoader.java | 63 +- .../github/loader/ItemAndBlockHolder.java | 6 +- .../glodblock/github/loader/RecipeLoader.java | 56 +- ...iHandler.java => AE2FC_NEIGuiHandler.java} | 12 +- .../glodblock/github/nei/NEI_FC_Config.java | 2 +- .../network/CPacketLevelMaintainer.java | 113 +- .../network/CPacketLevelTerminalCommands.java | 155 ++ .../github/network/CPacketRenamer.java | 107 +- .../network/SPacketLevelTerminalUpdate.java | 585 +++++++ .../network/wrapper/FCIndexedCodec.java | 32 + .../network/wrapper/FCNetworkWrapper.java | 177 +++ .../glodblock/github/proxy/CommonProxy.java | 12 +- .../glodblock/github/util/FCGuiColors.java | 46 + .../com/glodblock/github/util/NameConst.java | 6 + .../resources/assets/ae2fc/lang/en_US.lang | 18 + .../textures/blocks/level_terminal_bright.png | Bin 0 -> 144 bytes .../textures/blocks/level_terminal_dark.png | Bin 0 -> 1427 bytes .../textures/blocks/level_terminal_medium.png | Bin 0 -> 157 bytes .../ae2fc/textures/gui/level_maintainer.png | Bin 1376 -> 4044 bytes .../ae2fc/textures/gui/level_terminal.png | Bin 0 -> 3465 bytes .../assets/ae2fc/textures/gui/states0.png | Bin 1721 -> 1873 bytes .../assets/ae2fc/textures/gui/states2.png | Bin 0 -> 807 bytes .../items/wireless_interface_terminal.png | Bin 19687 -> 1157 bytes .../items/wireless_level_terminal.png | Bin 0 -> 474 bytes 80 files changed, 6129 insertions(+), 1745 deletions(-) create mode 100644 src/main/java/com/glodblock/github/api/ISide.java create mode 100644 src/main/java/com/glodblock/github/api/registries/ILevelTerminalRegistry.java create mode 100644 src/main/java/com/glodblock/github/api/registries/ILevelViewable.java create mode 100644 src/main/java/com/glodblock/github/api/registries/ILevelViewableAdapter.java rename src/main/java/com/glodblock/github/client/gui/{GuiFluidPatternTerminalCraftingStatus.java => GuiCraftingStatus.java} (53%) delete mode 100644 src/main/java/com/glodblock/github/client/gui/GuiInterfaceTerminalWireless.java create mode 100644 src/main/java/com/glodblock/github/client/gui/GuiInterfaceWireless.java create mode 100644 src/main/java/com/glodblock/github/client/gui/GuiLevelTerminal.java create mode 100644 src/main/java/com/glodblock/github/client/gui/GuiLevelWireless.java create mode 100644 src/main/java/com/glodblock/github/client/gui/container/ContainerLevelTerminal.java create mode 100644 src/main/java/com/glodblock/github/client/gui/container/ContainerLevelWireless.java create mode 100644 src/main/java/com/glodblock/github/common/item/ItemPartLevelTerminal.java create mode 100644 src/main/java/com/glodblock/github/common/item/ItemWirelessLevelTerminal.java create mode 100644 src/main/java/com/glodblock/github/common/parts/PartLevelTerminal.java create mode 100644 src/main/java/com/glodblock/github/coremod/registries/LevelTerminalRegistry.java create mode 100644 src/main/java/com/glodblock/github/coremod/registries/adapters/PartFluidLevelEmitterAdapter.java create mode 100644 src/main/java/com/glodblock/github/coremod/registries/adapters/PartLevelEmitterAdapter.java rename src/main/java/com/glodblock/github/coremod/transform/{NEITransfermer.java => NEITransformer.java} (94%) delete mode 100644 src/main/java/com/glodblock/github/coremod/transform/PacketCompressedNBTTransformer.java rename src/main/java/com/glodblock/github/crossmod/waila/tile/{LevelMaintainerWailaDataProvide.java => LevelMaintainerWailaDataProvider.java} (76%) rename src/main/java/com/glodblock/github/inventory/item/{IWirelessInterfaceTerminal.java => IClickableInTerminal.java} (74%) create mode 100644 src/main/java/com/glodblock/github/inventory/item/WirelessLevelTerminalInventory.java rename src/main/java/com/glodblock/github/nei/{NEIGuiHandler.java => AE2FC_NEIGuiHandler.java} (53%) create mode 100644 src/main/java/com/glodblock/github/network/CPacketLevelTerminalCommands.java create mode 100644 src/main/java/com/glodblock/github/network/SPacketLevelTerminalUpdate.java create mode 100644 src/main/java/com/glodblock/github/network/wrapper/FCIndexedCodec.java create mode 100644 src/main/java/com/glodblock/github/network/wrapper/FCNetworkWrapper.java create mode 100644 src/main/java/com/glodblock/github/util/FCGuiColors.java create mode 100644 src/main/resources/assets/ae2fc/textures/blocks/level_terminal_bright.png create mode 100644 src/main/resources/assets/ae2fc/textures/blocks/level_terminal_dark.png create mode 100644 src/main/resources/assets/ae2fc/textures/blocks/level_terminal_medium.png create mode 100644 src/main/resources/assets/ae2fc/textures/gui/level_terminal.png create mode 100644 src/main/resources/assets/ae2fc/textures/gui/states2.png create mode 100644 src/main/resources/assets/ae2fc/textures/items/wireless_level_terminal.png diff --git a/dependencies.gradle b/dependencies.gradle index 0df22fdd9..800ff1305 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,15 +1,48 @@ -// Add your dependencies here - +/* + * Add your dependencies here. Supported configurations: + * - api("group:name:version:classifier"): if you use the types from this dependency in the public API of this mod + * Available at runtime and compiletime for mods depending on this mod + * - implementation("g:n:v:c"): if you need this for internal implementation details of the mod, but none of it is visible via the public API + * Available at runtime but not compiletime for mods depending on this mod + * - compileOnly("g:n:v:c"): if the mod you're building doesn't need this dependency during runtime at all, e.g. for optional mods + * Not available at all for mods depending on this mod, only visible at compiletime for this mod + * - compileOnlyApi("g:n:v:c"): like compileOnly, but also visible at compiletime for mods depending on this mod + * Available at compiletime but not runtime for mods depending on this mod + * - runtimeOnlyNonPublishable("g:n:v:c"): if you want to include a mod in this mod's runClient/runServer runs, but not publish it as a dependency + * Not available at all for mods depending on this mod, only visible at runtime for this mod + * - devOnlyNonPublishable("g:n:v:c"): a combination of runtimeOnlyNonPublishable and compileOnly for dependencies present at both compiletime and runtime, + * but not published as Maven dependencies - useful for RFG-deobfuscated dependencies or local testing + * - runtimeOnly("g:n:v:c"): if you don't need this at compile time, but want it to be present at runtime + * Available at runtime for mods depending on this mod + * - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry + * - testCONFIG("g:n:v:c") - replace CONFIG by one of the above (except api), same as above but for the test sources instead of main + * + * - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name + * Requires you to enable usesShadowedDependencies in gradle.properties + * + * - compile("g:n:v:c"): deprecated, replace with "api" (works like the old "compile") or "implementation" (can be more efficient) + * + * You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed, + * but use this sparingly as it can break using your mod as another mod's dependency if you're not careful. + * + * To depend on obfuscated jars you can use `devOnlyNonPublishable(rfg.deobf("dep:spec:1.2.3"))` to fetch an obfuscated jar from maven, + * or `devOnlyNonPublishable(rfg.deobf(project.files("libs/my-mod-jar.jar")))` to use a file. + * + * Gradle names for some of the configuration can be misleading, compileOnlyApi and runtimeOnly both get published as dependencies in Maven, but compileOnly does not. + * The buildscript adds runtimeOnlyNonPublishable to also have a runtime dependency that's not published. + * + * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph + */ dependencies { api('com.github.GTNewHorizons:NotEnoughItems:2.4.5-GTNH:dev') - api('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-262-GTNH:dev') + api('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-271-GTNH-pre:dev') api('curse.maven:cofh-core-69162:2388751') api('com.github.GTNewHorizons:waila:1.6.2:dev') - compileOnly('com.github.GTNewHorizons:Baubles:1.0.1.16:dev') - compileOnly('com.github.GTNewHorizons:ExtraCells2:2.5.34:dev') { transitive = false } - compileOnly("com.github.GTNewHorizons:WirelessCraftingTerminal:1.10.1:dev") + implementation("com.github.GTNewHorizons:WirelessCraftingTerminal:1.10.1:dev") + compileOnly('com.github.GTNewHorizons:Baubles:1.0.1.16:dev') + compileOnly('com.github.GTNewHorizons:ExtraCells2:2.5.34:dev') { transitive = false } compileOnly('com.github.GTNewHorizons:ForestryMC:4.6.14:dev') compileOnly('com.github.GTNewHorizons:EnderIO:2.5.3:dev') compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.44.64:dev') { @@ -21,4 +54,6 @@ dependencies { compileOnly('com.github.GTNewHorizons:ThaumicEnergistics:1.4.13-GTNH:dev') { transitive = false } compileOnly('com.github.GTNewHorizons:GTplusplus:1.10.21:dev') { transitive = false } compileOnly("com.github.GTNewHorizons:Hodgepodge:2.3.19:dev") { transitive = false } + + runtimeOnlyNonPublishable("com.github.GTNewHorizons:DuraDisplay:1.1.7:dev") } diff --git a/src/main/java/com/glodblock/github/api/FluidCraftAPI.java b/src/main/java/com/glodblock/github/api/FluidCraftAPI.java index fc2ea89cb..003964247 100644 --- a/src/main/java/com/glodblock/github/api/FluidCraftAPI.java +++ b/src/main/java/com/glodblock/github/api/FluidCraftAPI.java @@ -5,6 +5,9 @@ import net.minecraftforge.fluids.Fluid; +import com.glodblock.github.api.registries.ILevelTerminalRegistry; +import com.glodblock.github.coremod.registries.LevelTerminalRegistry; + public final class FluidCraftAPI implements IFluidCraftAPI { private static final FluidCraftAPI API = new FluidCraftAPI(); @@ -42,4 +45,9 @@ public boolean isBlacklistedInStorage(Class fluid) { public boolean isBlacklistedInDisplay(Class fluid) { return blacklistedDispFluids.contains(fluid); } + + @Override + public ILevelTerminalRegistry levelTerminalRegistry() { + return LevelTerminalRegistry.instance(); + } } diff --git a/src/main/java/com/glodblock/github/api/IFluidCraftAPI.java b/src/main/java/com/glodblock/github/api/IFluidCraftAPI.java index fbf9e47d8..07b0126f1 100644 --- a/src/main/java/com/glodblock/github/api/IFluidCraftAPI.java +++ b/src/main/java/com/glodblock/github/api/IFluidCraftAPI.java @@ -2,6 +2,8 @@ import net.minecraftforge.fluids.Fluid; +import com.glodblock.github.api.registries.ILevelTerminalRegistry; + @SuppressWarnings("unused") public interface IFluidCraftAPI { @@ -24,4 +26,9 @@ public interface IFluidCraftAPI { * Mostly for internal use; queries whether the fluid is blacklisted from being displayed. */ boolean isBlacklistedInDisplay(Class fluid); + + /** + * Get instance of `ILevelTerminalRegistry` to add new supported machines into terminal + */ + ILevelTerminalRegistry levelTerminalRegistry(); } diff --git a/src/main/java/com/glodblock/github/api/ISide.java b/src/main/java/com/glodblock/github/api/ISide.java new file mode 100644 index 000000000..3fade747d --- /dev/null +++ b/src/main/java/com/glodblock/github/api/ISide.java @@ -0,0 +1,8 @@ +package com.glodblock.github.api; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface ISide { + + ForgeDirection getSide(); +} diff --git a/src/main/java/com/glodblock/github/api/registries/ILevelTerminalRegistry.java b/src/main/java/com/glodblock/github/api/registries/ILevelTerminalRegistry.java new file mode 100644 index 000000000..d00c4d16e --- /dev/null +++ b/src/main/java/com/glodblock/github/api/registries/ILevelTerminalRegistry.java @@ -0,0 +1,20 @@ +package com.glodblock.github.api.registries; + +import java.util.Set; + +import appeng.api.networking.IGridHost; + +public interface ILevelTerminalRegistry { + + void register(Class clazz); + + void register(Class aeClass, ILevelViewableAdapter adapter); + + Set> getSupportedClasses(); + + boolean isAdopted(Class clazz); + + Class getAdopted(Class clazz); + + ILevelViewableAdapter getAdapter(Class clazz); +} diff --git a/src/main/java/com/glodblock/github/api/registries/ILevelViewable.java b/src/main/java/com/glodblock/github/api/registries/ILevelViewable.java new file mode 100644 index 000000000..2f1926021 --- /dev/null +++ b/src/main/java/com/glodblock/github/api/registries/ILevelViewable.java @@ -0,0 +1,53 @@ +package com.glodblock.github.api.registries; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import com.glodblock.github.api.ISide; + +import appeng.api.implementations.tiles.ISegmentedInventory; +import appeng.api.networking.IGridHost; +import appeng.api.util.DimensionalCoord; +import appeng.helpers.ICustomNameObject; + +public interface ILevelViewable extends IGridHost, ISide, ISegmentedInventory, ICustomNameObject { + + DimensionalCoord getLocation(); + + TileEntity getTile(); + + default long getSortValue() { + TileEntity te = getTile(); + return ((long) te.zCoord << 24) ^ ((long) te.xCoord << 8) ^ te.yCoord; + } + + default boolean shouldDisplay() { + return true; + } + + /** + * Number of rows to expect. This is used with {@link #rowSize()} to determine how to render the slots. + */ + default int rows() { + return 1; + }; + + /** + * Number of slots per row. + */ + default int rowSize() { + return 1; + }; + + default ItemStack getSelfItemStack() { + return null; + } + + /** + * "Target" Display representation + */ + default ItemStack getDisplayItemStack() { + return null; + } + +} diff --git a/src/main/java/com/glodblock/github/api/registries/ILevelViewableAdapter.java b/src/main/java/com/glodblock/github/api/registries/ILevelViewableAdapter.java new file mode 100644 index 000000000..890b3f778 --- /dev/null +++ b/src/main/java/com/glodblock/github/api/registries/ILevelViewableAdapter.java @@ -0,0 +1,8 @@ +package com.glodblock.github.api.registries; + +import appeng.api.networking.IGridHost; + +public interface ILevelViewableAdapter extends ILevelViewable { + + ILevelViewable adapt(IGridHost gridHost); +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminalCraftingStatus.java b/src/main/java/com/glodblock/github/client/gui/GuiCraftingStatus.java similarity index 53% rename from src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminalCraftingStatus.java rename to src/main/java/com/glodblock/github/client/gui/GuiCraftingStatus.java index decac25b2..ae50095d0 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternTerminalCraftingStatus.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiCraftingStatus.java @@ -2,31 +2,31 @@ import net.minecraft.client.gui.GuiButton; import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.item.ItemStack; import com.glodblock.github.common.item.ItemWirelessUltraTerminal; import com.glodblock.github.common.parts.PartFluidPatternTerminal; import com.glodblock.github.common.parts.PartFluidPatternTerminalEx; import com.glodblock.github.common.parts.PartFluidTerminal; +import com.glodblock.github.common.parts.PartLevelTerminal; import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.item.IWirelessTerminal; import com.glodblock.github.inventory.item.WirelessFluidTerminalInventory; import com.glodblock.github.inventory.item.WirelessInterfaceTerminalInventory; +import com.glodblock.github.inventory.item.WirelessLevelTerminalInventory; import com.glodblock.github.inventory.item.WirelessPatternTerminalInventory; import com.glodblock.github.loader.ItemAndBlockHolder; import com.glodblock.github.util.Ae2ReflectClient; import appeng.api.storage.ITerminalHost; -import appeng.client.gui.implementations.GuiCraftingStatus; import appeng.client.gui.widgets.GuiTabButton; -public class GuiFluidPatternTerminalCraftingStatus extends GuiCraftingStatus { +public class GuiCraftingStatus extends appeng.client.gui.implementations.GuiCraftingStatus { private GuiTabButton originalGuiBtn; private final ITerminalHost host; - public GuiFluidPatternTerminalCraftingStatus(InventoryPlayer inventoryPlayer, ITerminalHost te) { + public GuiCraftingStatus(InventoryPlayer inventoryPlayer, ITerminalHost te) { super(inventoryPlayer, te); host = te; } @@ -34,20 +34,23 @@ public GuiFluidPatternTerminalCraftingStatus(InventoryPlayer inventoryPlayer, IT @Override public void initGui() { if (host instanceof PartFluidPatternTerminal) - Ae2ReflectClient.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL, 1)); + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.FLUID_TERMINAL.stack()); else if (host instanceof PartFluidPatternTerminalEx) - Ae2ReflectClient.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL_EX, 1)); - else if (host instanceof PartFluidTerminal) { - Ae2ReflectClient.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.FLUID_TERM, 1)); - } else if (host instanceof IWirelessTerminal && ((IWirelessTerminal) host).isUniversal(host)) { - Ae2ReflectClient.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.WIRELESS_ULTRA_TERM, 1)); - } else if (host instanceof WirelessFluidTerminalInventory) { - Ae2ReflectClient.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.WIRELESS_FLUID_TERM, 1)); - } else if (host instanceof WirelessPatternTerminalInventory) { - Ae2ReflectClient.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.WIRELESS_PATTERN_TERM, 1)); - } else if (host instanceof WirelessInterfaceTerminalInventory) { - Ae2ReflectClient.rewriteIcon(this, new ItemStack(ItemAndBlockHolder.WIRELESS_INTERFACE_TERM, 1)); - } + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.FLUID_TERMINAL_EX.stack()); + else if (host instanceof PartFluidTerminal) + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.FLUID_TERM.stack()); + else if (host instanceof PartLevelTerminal) + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.LEVEL_TERMINAL.stack()); + else if (host instanceof IWirelessTerminal terminal && terminal.isUniversal(host)) + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.WIRELESS_ULTRA_TERM.stack()); + else if (host instanceof WirelessFluidTerminalInventory) + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.WIRELESS_FLUID_TERM.stack()); + else if (host instanceof WirelessPatternTerminalInventory) + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.WIRELESS_PATTERN_TERM.stack()); + else if (host instanceof WirelessInterfaceTerminalInventory) + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.WIRELESS_INTERFACE_TERM.stack()); + else if (host instanceof WirelessLevelTerminalInventory) + Ae2ReflectClient.rewriteIcon(this, ItemAndBlockHolder.WIRELESS_LEVEL_TERM.stack()); super.initGui(); originalGuiBtn = Ae2ReflectClient.getOriginalGuiButton(this); } @@ -59,14 +62,17 @@ protected void actionPerformed(final GuiButton btn) { else if (host instanceof PartFluidPatternTerminalEx) InventoryHandler.switchGui(GuiType.FLUID_PATTERN_TERMINAL_EX); else if (host instanceof PartFluidTerminal) InventoryHandler.switchGui(GuiType.FLUID_TERMINAL); - else if (host instanceof IWirelessTerminal && ((IWirelessTerminal) host).isUniversal(host)) InventoryHandler - .switchGui(ItemWirelessUltraTerminal.readMode(((IWirelessTerminal) host).getItemStack())); + else if (host instanceof PartLevelTerminal) InventoryHandler.switchGui(GuiType.LEVEL_TERMINAL); + else if (host instanceof IWirelessTerminal terminal && terminal.isUniversal(host)) + InventoryHandler.switchGui(ItemWirelessUltraTerminal.readMode(terminal.getItemStack())); else if (host instanceof WirelessFluidTerminalInventory) InventoryHandler.switchGui(GuiType.WIRELESS_FLUID_TERMINAL); else if (host instanceof WirelessPatternTerminalInventory) InventoryHandler.switchGui(GuiType.WIRELESS_FLUID_PATTERN_TERMINAL); else if (host instanceof WirelessInterfaceTerminalInventory) InventoryHandler.switchGui(GuiType.WIRELESS_INTERFACE_TERMINAL); + else if (host instanceof WirelessLevelTerminalInventory) + InventoryHandler.switchGui(GuiType.WIRELESS_LEVEL_TERMINAL); } else { super.actionPerformed(btn); } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiDualInterface.java b/src/main/java/com/glodblock/github/client/gui/GuiDualInterface.java index 7d6c5c819..5174f7e1f 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiDualInterface.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiDualInterface.java @@ -6,13 +6,12 @@ import org.lwjgl.input.Mouse; -import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.ContainerDualInterface; import com.glodblock.github.common.parts.PartFluidInterface; import com.glodblock.github.common.tile.TileFluidInterface; +import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.loader.ItemAndBlockHolder; -import com.glodblock.github.network.CPacketSwitchGuis; import com.glodblock.github.util.ModAndClassUtil; import com.glodblock.github.util.NameConst; @@ -148,9 +147,9 @@ protected void actionPerformed(final GuiButton btn) { super.actionPerformed(btn); final boolean backwards = Mouse.isButtonDown(1); if (btn == this.priority) { - FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(GuiType.PRIORITY)); + InventoryHandler.switchGui(GuiType.PRIORITY); } else if (btn == this.switcher) { - FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(GuiType.DUAL_INTERFACE_FLUID)); + InventoryHandler.switchGui(GuiType.DUAL_INTERFACE_FLUID); } else if (btn == this.interfaceMode) { NetworkHandler.instance.sendToServer(new PacketConfigButton(Settings.INTERFACE_TERMINAL, backwards)); } else if (btn == this.BlockMode) { diff --git a/src/main/java/com/glodblock/github/client/gui/GuiEssentiaTerminal.java b/src/main/java/com/glodblock/github/client/gui/GuiEssentiaTerminal.java index d2aa589c1..f9ae87652 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiEssentiaTerminal.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiEssentiaTerminal.java @@ -11,6 +11,8 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; + import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.ContainerEssentiaMonitor; import com.glodblock.github.client.me.EssentiaRepo; @@ -21,16 +23,13 @@ import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.item.IWirelessTerminal; import com.glodblock.github.network.CPacketFluidUpdate; -import com.glodblock.github.util.Ae2ReflectClient; import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEItemStack; import appeng.client.me.SlotME; -import appeng.client.render.AppEngRenderItem; public class GuiEssentiaTerminal extends GuiFluidMonitor { - private final AppEngRenderItem stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); protected EntityPlayer player; public GuiEssentiaTerminal(InventoryPlayer inventoryPlayer, IWirelessTerminal te) { @@ -64,13 +63,15 @@ public boolean drawSlot0(Slot slot) { AspectUtil.getAspectFromGas(fluidStack), fluidStack.amount); IAEItemStack gas = stack.copy().setStackSize(stack.getStackSize() / AspectUtil.R); - stackSizeRenderer.setAeStack(gas); - stackSizeRenderer.renderItemOverlayIntoGUI( + aeRenderItem.setAeStack(gas); + GL11.glTranslatef(0.0f, 0.0f, 200.0f); + aeRenderItem.renderItemOverlayIntoGUI( fontRendererObj, mc.getTextureManager(), gas.getItemStack(), slot.xDisplayPosition, slot.yDisplayPosition); + GL11.glTranslatef(0.0f, 0.0f, -200.0f); return false; } return true; diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java b/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java index ff8404f37..75fda0058 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFCImgButton.java @@ -59,6 +59,13 @@ public GuiFCImgButton(final int x, final int y, final String idx, final String v this.registerApp(15, "PATTERN_EX_TEM", "YES", "pattern_terminal_ex_w"); this.registerApp(16, "FILL_PATTERN", "DO_FILL", "fill_pattern"); this.registerApp(17, "NOT_FILL_PATTERN", "DONT_FILL", "not_fill_pattern"); + this.registerApp(20, "LEVEL_TEM", "YES", "level_terminal_w"); + this.registerApp(21, "SWITCH", "ON", "edit"); + this.registerApp(22, "SWITCH", "OFF", "view"); + this.registerApp(21, "SWITCH", "ENABLE", "enable"); + this.registerApp(22, "SWITCH", "DISABLE", "disable"); + this.registerApp(23, "CONFIG", "YES", "open_configuration"); + this.registerApp(24, "HIGHLIGHT", "YES", "block_highlight"); } } @@ -110,6 +117,10 @@ public String getCurrentValue() { return this.currentValue; } + public boolean getMouseIn() { + return this.field_146123_n; + } + public void set(final String e) { if (!this.currentValue.equals(e)) { this.currentValue = e; diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftAmount.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftAmount.java index f535b0c5f..cc94d53f5 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftAmount.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftAmount.java @@ -2,7 +2,6 @@ import net.minecraft.client.gui.GuiButton; import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.item.ItemStack; import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.base.FCGuiAmount; @@ -10,8 +9,10 @@ import com.glodblock.github.common.parts.PartFluidPatternTerminal; import com.glodblock.github.common.parts.PartFluidPatternTerminalEx; import com.glodblock.github.common.parts.PartFluidTerminal; +import com.glodblock.github.common.parts.PartLevelTerminal; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.item.IWirelessTerminal; +import com.glodblock.github.inventory.item.WirelessLevelTerminalInventory; import com.glodblock.github.inventory.item.WirelessPatternTerminalInventory; import com.glodblock.github.loader.ItemAndBlockHolder; import com.glodblock.github.network.CPacketCraftRequest; @@ -65,20 +66,26 @@ protected void actionPerformed(final GuiButton btn) { @Override protected void setOriginGUI(Object target) { if (target instanceof PartFluidPatternTerminal) { - this.myIcon = new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL, 1); + this.myIcon = ItemAndBlockHolder.FLUID_TERMINAL.stack(); this.originalGui = GuiType.FLUID_PATTERN_TERMINAL; } else if (target instanceof PartFluidPatternTerminalEx) { - this.myIcon = new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL_EX, 1); + this.myIcon = ItemAndBlockHolder.FLUID_TERMINAL_EX.stack(); this.originalGui = GuiType.FLUID_PATTERN_TERMINAL_EX; } else if (target instanceof PartFluidTerminal) { - this.myIcon = new ItemStack(ItemAndBlockHolder.FLUID_TERM, 1); + this.myIcon = ItemAndBlockHolder.FLUID_TERM.stack(); this.originalGui = GuiType.FLUID_TERMINAL; - } else if (target instanceof IWirelessTerminal && ((IWirelessTerminal) target).isUniversal(target)) { - this.myIcon = new ItemStack(ItemAndBlockHolder.WIRELESS_ULTRA_TERM, 1); - this.originalGui = ItemWirelessUltraTerminal.readMode(((IWirelessTerminal) target).getItemStack()); + } else if (target instanceof PartLevelTerminal) { + myIcon = ItemAndBlockHolder.LEVEL_TERMINAL.stack(); + originalGui = GuiType.LEVEL_TERMINAL; + } else if (target instanceof IWirelessTerminal terminal && terminal.isUniversal(target)) { + this.myIcon = ItemAndBlockHolder.WIRELESS_ULTRA_TERM.stack(); + this.originalGui = ItemWirelessUltraTerminal.readMode(terminal.getItemStack()); } else if (target instanceof WirelessPatternTerminalInventory) { - this.myIcon = new ItemStack(ItemAndBlockHolder.WIRELESS_PATTERN_TERM, 1); + this.myIcon = ItemAndBlockHolder.WIRELESS_PATTERN_TERM.stack(); this.originalGui = GuiType.FLUID_TERMINAL; + } else if (target instanceof WirelessLevelTerminalInventory) { + myIcon = ItemAndBlockHolder.LEVEL_TERMINAL.stack(); + originalGui = GuiType.WIRELESS_LEVEL_TERMINAL; } } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftConfirm.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftConfirm.java index 2ed531213..4ddbaea44 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftConfirm.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidCraftConfirm.java @@ -2,37 +2,42 @@ import net.minecraft.entity.player.InventoryPlayer; -import com.glodblock.github.FluidCraft; import com.glodblock.github.common.item.ItemWirelessUltraTerminal; import com.glodblock.github.common.parts.PartFluidPatternTerminal; import com.glodblock.github.common.parts.PartFluidPatternTerminalEx; +import com.glodblock.github.common.parts.PartLevelTerminal; +import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.item.IWirelessTerminal; +import com.glodblock.github.inventory.item.WirelessLevelTerminalInventory; import com.glodblock.github.inventory.item.WirelessPatternTerminalInventory; -import com.glodblock.github.network.CPacketSwitchGuis; import appeng.api.storage.ITerminalHost; import appeng.client.gui.implementations.GuiCraftConfirm; public class GuiFluidCraftConfirm extends GuiCraftConfirm { - private GuiType OriginalGui; + private GuiType originalGui; public GuiFluidCraftConfirm(final InventoryPlayer inventoryPlayer, final ITerminalHost te) { super(inventoryPlayer, te); if (te instanceof PartFluidPatternTerminal) { - this.OriginalGui = GuiType.FLUID_PATTERN_TERMINAL; + this.originalGui = GuiType.FLUID_PATTERN_TERMINAL; } else if (te instanceof PartFluidPatternTerminalEx) { - this.OriginalGui = GuiType.FLUID_PATTERN_TERMINAL_EX; - } else if (te instanceof IWirelessTerminal && ((IWirelessTerminal) te).isUniversal(te)) { - this.OriginalGui = ItemWirelessUltraTerminal.readMode(((IWirelessTerminal) te).getItemStack()); + this.originalGui = GuiType.FLUID_PATTERN_TERMINAL_EX; + } else if (te instanceof PartLevelTerminal) { + originalGui = GuiType.LEVEL_TERMINAL; + } else if (te instanceof IWirelessTerminal terminal && terminal.isUniversal(te)) { + this.originalGui = ItemWirelessUltraTerminal.readMode(terminal.getItemStack()); } else if (te instanceof WirelessPatternTerminalInventory) { - this.OriginalGui = GuiType.FLUID_TERMINAL; + this.originalGui = GuiType.FLUID_TERMINAL; + } else if (te instanceof WirelessLevelTerminalInventory) { + originalGui = GuiType.WIRELESS_LEVEL_TERMINAL; } } @Override public void switchToOriginalGUI() { - FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(this.OriginalGui)); + InventoryHandler.switchGui(originalGui); } } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidInterface.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidInterface.java index 50059d53d..f0a70f33f 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidInterface.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidInterface.java @@ -17,11 +17,11 @@ import com.glodblock.github.common.parts.PartFluidInterface; import com.glodblock.github.inventory.IAEFluidTank; import com.glodblock.github.inventory.IDualHost; +import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.gui.MouseRegionManager; import com.glodblock.github.inventory.gui.TankMouseHandler; import com.glodblock.github.loader.ItemAndBlockHolder; -import com.glodblock.github.network.CPacketSwitchGuis; import com.glodblock.github.util.NameConst; import com.glodblock.github.util.RenderUtil; @@ -117,7 +117,7 @@ public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { protected void actionPerformed(final GuiButton btn) { super.actionPerformed(btn); if (btn == this.switcher) { - FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(GuiType.DUAL_INTERFACE)); + InventoryHandler.switchGui(GuiType.DUAL_INTERFACE); } } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidLevelEmitter.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidLevelEmitter.java index 13464de0c..ad58d53f0 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidLevelEmitter.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidLevelEmitter.java @@ -7,7 +7,6 @@ import com.glodblock.github.client.gui.container.ContainerFluidLevelEmitter; import com.glodblock.github.common.parts.PartFluidLevelEmitter; import com.glodblock.github.network.CPacketValueConfig; -import com.glodblock.github.util.Ae2ReflectClient; import com.glodblock.github.util.NameConst; import appeng.api.config.RedstoneMode; @@ -16,7 +15,6 @@ import appeng.client.gui.implementations.GuiUpgradeable; import appeng.client.gui.widgets.GuiImgButton; import appeng.client.gui.widgets.GuiNumberBox; -import appeng.client.render.AppEngRenderItem; import appeng.core.AEConfig; import appeng.core.AELog; import appeng.core.localization.GuiColors; @@ -25,7 +23,6 @@ public class GuiFluidLevelEmitter extends GuiUpgradeable { private GuiNumberBox level; - private final AppEngRenderItem stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); private GuiButton plus1; private GuiButton plus10; private GuiButton plus100; @@ -82,7 +79,7 @@ protected void addButtons() { @Override public void drawFG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { this.fontRendererObj.drawString( - NameConst.i18n(NameConst.GUI_FLUID_LEVEL_EMITTER), + getGuiDisplayName(NameConst.i18n(NameConst.GUI_FLUID_LEVEL_EMITTER)), 8, 6, GuiColors.UpgradableTitle.getColor()); diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternEncoder.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternEncoder.java index dd1211a92..7ca1fdd16 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternEncoder.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidPatternEncoder.java @@ -13,6 +13,8 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; + import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.ContainerFluidPatternEncoder; import com.glodblock.github.common.item.ItemFluidPacket; @@ -21,12 +23,10 @@ import com.glodblock.github.inventory.slot.ISlotFluid; import com.glodblock.github.inventory.slot.SlotSingleItem; import com.glodblock.github.network.CPacketEncodePattern; -import com.glodblock.github.util.Ae2ReflectClient; import com.glodblock.github.util.NameConst; import appeng.api.storage.data.IAEItemStack; import appeng.client.gui.AEBaseGui; -import appeng.client.render.AppEngRenderItem; import appeng.core.localization.GuiText; public class GuiFluidPatternEncoder extends AEBaseGui { @@ -35,7 +35,6 @@ public class GuiFluidPatternEncoder extends AEBaseGui { private final ContainerFluidPatternEncoder cont; private final MouseRegionManager mouseRegions = new MouseRegionManager(this); - private final AppEngRenderItem stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); public GuiFluidPatternEncoder(InventoryPlayer ipl, TileFluidPatternEncoder tile) { super(new ContainerFluidPatternEncoder(ipl, tile)); @@ -95,13 +94,15 @@ public void drawSlot0(Slot slot) { if (ItemFluidPacket.getFluidStack(stack) != null && ItemFluidPacket.getFluidStack(stack).amount > 0) fake.setStackSize(ItemFluidPacket.getFluidStack(stack).amount); } - stackSizeRenderer.setAeStack(fake); - stackSizeRenderer.renderItemOverlayIntoGUI( + aeRenderItem.setAeStack(fake); + GL11.glTranslatef(0.0f, 0.0f, 200.0f); + aeRenderItem.renderItemOverlayIntoGUI( fontRendererObj, mc.getTextureManager(), stack.getItemStack(), slot.xDisplayPosition, slot.yDisplayPosition); + GL11.glTranslatef(0.0f, 0.0f, -200.0f); } else { super.func_146977_a(slot); } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidStorageBus.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidStorageBus.java index b793de511..d216071ce 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidStorageBus.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidStorageBus.java @@ -9,9 +9,9 @@ import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.ContainerFluidStorageBus; import com.glodblock.github.common.parts.PartFluidStorageBus; +import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.network.CPacketFluidPatternTermBtns; -import com.glodblock.github.network.CPacketSwitchGuis; import com.glodblock.github.util.NameConst; import appeng.api.config.AccessRestriction; @@ -93,7 +93,7 @@ protected void actionPerformed(final GuiButton btn) { } else if (btn == this.clear) { FluidCraft.proxy.netHandler.sendToServer(new CPacketFluidPatternTermBtns("StorageBus.Action", "Clear")); } else if (btn == this.priority) { - FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(GuiType.PRIORITY)); + InventoryHandler.switchGui(GuiType.PRIORITY); } else if (btn == this.rwMode) { NetworkHandler.instance.sendToServer(new PacketConfigButton(this.rwMode.getSetting(), backwards)); } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiFluidTerminal.java b/src/main/java/com/glodblock/github/client/gui/GuiFluidTerminal.java index 31209e17b..76a866d24 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiFluidTerminal.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiFluidTerminal.java @@ -22,7 +22,6 @@ import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.network.CPacketFluidUpdate; -import com.glodblock.github.util.Ae2ReflectClient; import com.glodblock.github.util.ModAndClassUtil; import com.glodblock.github.util.Util; import com.mitchej123.hodgepodge.textures.IPatchedTextureAtlasSprite; @@ -31,12 +30,10 @@ import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEItemStack; import appeng.client.me.SlotME; -import appeng.client.render.AppEngRenderItem; import appeng.container.slot.AppEngSlot; public class GuiFluidTerminal extends GuiFluidMonitor { - private final AppEngRenderItem stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); protected EntityPlayer player; public ContainerFluidMonitor container; @@ -84,13 +81,15 @@ public boolean drawSlot0(Slot slot) { if (stack == null) return true; FluidStack fluidStack = ItemFluidDrop.getFluidStack(slot.getStack()); this.drawWidget(slot.xDisplayPosition, slot.yDisplayPosition, fluidStack.getFluid()); - stackSizeRenderer.setAeStack(stack); - stackSizeRenderer.renderItemOverlayIntoGUI( + aeRenderItem.setAeStack(stack); + GL11.glTranslatef(0.0f, 0.0f, 200.0f); + aeRenderItem.renderItemOverlayIntoGUI( fontRendererObj, mc.getTextureManager(), stack.getItemStack(), slot.xDisplayPosition, slot.yDisplayPosition); + GL11.glTranslatef(0.0f, 0.0f, -200.0f); return false; } return true; diff --git a/src/main/java/com/glodblock/github/client/gui/GuiInterfaceTerminalWireless.java b/src/main/java/com/glodblock/github/client/gui/GuiInterfaceTerminalWireless.java deleted file mode 100644 index 4b726d295..000000000 --- a/src/main/java/com/glodblock/github/client/gui/GuiInterfaceTerminalWireless.java +++ /dev/null @@ -1,769 +0,0 @@ -package com.glodblock.github.client.gui; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; - -import net.minecraft.client.gui.GuiButton; -import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.util.ChatComponentTranslation; -import net.minecraft.world.World; -import net.minecraftforge.common.util.ForgeDirection; - -import org.lwjgl.input.Mouse; -import org.lwjgl.opengl.GL11; - -import com.glodblock.github.FluidCraft; -import com.glodblock.github.client.gui.base.FCBaseMEGui; -import com.glodblock.github.client.gui.container.ContainerInterfaceWireless; -import com.glodblock.github.inventory.InventoryHandler; -import com.glodblock.github.inventory.gui.GuiType; -import com.glodblock.github.inventory.item.IWirelessTerminal; -import com.glodblock.github.network.CPacketRenamer; -import com.glodblock.github.util.ModAndClassUtil; -import com.glodblock.github.util.Util; -import com.google.common.collect.HashMultimap; - -import appeng.api.AEApi; -import appeng.api.config.ActionItems; -import appeng.api.config.Settings; -import appeng.api.config.TerminalStyle; -import appeng.api.config.YesNo; -import appeng.api.util.WorldCoord; -import appeng.client.gui.widgets.GuiImgButton; -import appeng.client.gui.widgets.GuiScrollbar; -import appeng.client.gui.widgets.GuiTabButton; -import appeng.client.gui.widgets.IDropToFillTextField; -import appeng.client.gui.widgets.MEGuiTextField; -import appeng.client.me.ClientDCInternalInv; -import appeng.client.me.SlotDisconnected; -import appeng.client.render.BlockPosHighlighter; -import appeng.container.slot.AppEngSlot; -import appeng.core.AEConfig; -import appeng.core.CommonHelper; -import appeng.core.localization.ButtonToolTips; -import appeng.core.localization.GuiColors; -import appeng.core.localization.GuiText; -import appeng.core.localization.PlayerMessages; -import appeng.helpers.PatternHelper; -import appeng.integration.IntegrationRegistry; -import appeng.integration.IntegrationType; -import appeng.util.Platform; - -public class GuiInterfaceTerminalWireless extends FCBaseMEGui implements IDropToFillTextField { - - protected int offsetY; - private static final int MAGIC_HEIGHT_NUMBER = 52 + 99; - private static final int offsetX = 21; - - private final HashMap byId = new HashMap<>(); - private final HashMultimap byName = HashMultimap.create(); - private final HashMap blockPosHashMap = new HashMap<>(); - private final HashMap guiButtonHashMap = new HashMap<>(); - private final ArrayList names = new ArrayList<>(); - private final ArrayList lines = new ArrayList<>(); - private final Set matchedStacks = new HashSet<>(); - - private final Map> cachedSearches = new WeakHashMap<>(); - - protected static String searchFieldOutputsText = ""; - protected static String searchFieldInputsText = ""; - protected static String searchFieldNamesText = ""; - private final MEGuiTextField searchFieldOutputs; - private final MEGuiTextField searchFieldInputs; - private final MEGuiTextField searchFieldNames; - private final GuiImgButton guiButtonHideFull; - private final GuiImgButton guiButtonAssemblersOnly; - private final GuiImgButton guiButtonBrokenRecipes; - private GuiImgButton searchStringSave; - private GuiImgButton terminalStyleBox; - private boolean refreshList = false; - protected static boolean onlyMolecularAssemblers = false; - protected static boolean onlyBrokenRecipes = false; - protected GuiTabButton craftingStatusBtn; - - private int rows = 3; - - private static final String MOLECULAR_ASSEMBLER = "tile.appliedenergistics2.BlockMolecularAssembler"; - - public GuiInterfaceTerminalWireless(final InventoryPlayer inventoryPlayer, final IWirelessTerminal te) { - super(inventoryPlayer, new ContainerInterfaceWireless(inventoryPlayer, te)); - - this.setScrollBar(new GuiScrollbar()); - this.xSize = 208; - this.ySize = 255; - - searchFieldInputs = new MEGuiTextField(86, 12, ButtonToolTips.SearchFieldInputs.getLocal()) { - - @Override - public void onTextChange(final String oldText) { - refreshList(); - } - }; - - searchFieldOutputs = new MEGuiTextField(86, 12, ButtonToolTips.SearchFieldOutputs.getLocal()) { - - @Override - public void onTextChange(final String oldText) { - refreshList(); - } - }; - - searchFieldNames = new MEGuiTextField(71, 12, ButtonToolTips.SearchFieldNames.getLocal()) { - - @Override - public void onTextChange(final String oldText) { - refreshList(); - } - }; - searchFieldNames.setFocused(true); - - guiButtonAssemblersOnly = new GuiImgButton(0, 0, Settings.ACTIONS, null); - guiButtonHideFull = new GuiImgButton(0, 0, Settings.ACTIONS, null); - guiButtonBrokenRecipes = new GuiImgButton(0, 0, Settings.ACTIONS, null); - } - - @Override - public int getOffsetY() { - return this.offsetY; - } - - @Override - public void setOffsetY(int y) { - this.offsetY = y; - } - - private void setScrollBar() { - this.getScrollBar().setTop(52).setLeft(189).setHeight(this.rows * 18 - 2); - this.getScrollBar().setRange(0, this.lines.size() - this.rows, 2); - } - - @Override - public void initGui() { - super.initGui(); - this.rows = calculateRowsCount(); - this.ySize = MAGIC_HEIGHT_NUMBER + this.rows * 18; - final int unusedSpace = this.height - this.ySize; - this.guiTop = (int) Math.floor(unusedSpace / (unusedSpace < 0 ? 3.8f : 2.0f)); - this.offsetY = this.guiTop + 8; - this.buttonList.add( - this.terminalStyleBox = new GuiImgButton( - this.guiLeft - 18, - this.offsetY, - Settings.TERMINAL_STYLE, - AEConfig.instance.settings.getSetting(Settings.TERMINAL_STYLE))); - this.offsetY += 20; - this.buttonList.add( - this.searchStringSave = new GuiImgButton( - this.guiLeft - 18, - this.offsetY, - Settings.SAVE_SEARCH, - AEConfig.instance.settings.getSetting(Settings.SAVE_SEARCH))); - this.offsetY += 20; - - searchFieldInputs.x = guiLeft + Math.max(32, offsetX); - searchFieldInputs.y = guiTop + 25; - - searchFieldOutputs.x = guiLeft + Math.max(32, offsetX); - searchFieldOutputs.y = guiTop + 38; - - searchFieldNames.x = guiLeft + Math.max(32, offsetX) + 99; - searchFieldNames.y = guiTop + 38; - - guiButtonAssemblersOnly.xPosition = guiLeft + Math.max(32, offsetX) + 99; - guiButtonAssemblersOnly.yPosition = guiTop + 20; - - guiButtonHideFull.xPosition = guiButtonAssemblersOnly.xPosition + 18; - guiButtonHideFull.yPosition = guiTop + 20; - - guiButtonBrokenRecipes.xPosition = guiButtonHideFull.xPosition + 18; - guiButtonBrokenRecipes.yPosition = guiTop + 20; - - terminalStyleBox.xPosition = guiLeft - 18; - terminalStyleBox.yPosition = guiTop + 8; - this.buttonList.add( - this.craftingStatusBtn = new GuiTabButton( - this.guiLeft + this.xSize - 24, - this.guiTop - 4, - 2 + 11 * 16, - GuiText.CraftingStatus.getLocal(), - itemRender)); - this.craftingStatusBtn.setHideEdge(13); // GuiTabButton implementation // - - if (ModAndClassUtil.isSearchBar && (AEConfig.instance.preserveSearchBar || this.isSubGui())) { - setSearchString(); - } - - this.setScrollBar(); - this.repositionSlots(); - this.initGuiDone(); - } - - @Override - public void onGuiClosed() { - super.onGuiClosed(); - searchFieldOutputsText = this.searchFieldOutputs.getText(); - searchFieldInputsText = this.searchFieldInputs.getText(); - searchFieldNamesText = this.searchFieldNames.getText(); - } - - public void setSearchString() { - this.searchFieldOutputs.setText(searchFieldOutputsText); - this.searchFieldInputs.setText(searchFieldInputsText); - this.searchFieldNames.setText(searchFieldNamesText); - } - - protected void repositionSlots() { - for (final Object obj : this.inventorySlots.inventorySlots) { - if (obj instanceof final AppEngSlot slot) { - slot.yDisplayPosition = this.ySize + slot.getY() - 78 - 7; - } - } - } - - protected int calculateRowsCount() { - final int maxRows = this.getMaxRows(); - final boolean hasNEI = IntegrationRegistry.INSTANCE.isEnabled(IntegrationType.NEI); - final int input = 22; - final int topPanel = 18; - final int NEIPadding = hasNEI ? input + topPanel : 0; - final int extraSpace = this.height - MAGIC_HEIGHT_NUMBER - NEIPadding; - - return Math.max(3, Math.min(maxRows, extraSpace / 18)); - } - - @Override - public void drawFG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { - fontRendererObj.drawString( - getGuiDisplayName(GuiText.InterfaceTerminal.getLocal()), - 8, - 6, - GuiColors.InterfaceTerminalTitle.getColor()); - fontRendererObj.drawString( - GuiText.inventory.getLocal(), - GuiInterfaceTerminalWireless.offsetX + 2, - this.ySize - 96, - GuiColors.InterfaceTerminalInventory.getColor()); - - int offset = 51; - final int ex = getScrollBar().getCurrentScroll(); - for (int x = 0; x < this.rows && ex + x < this.lines.size(); x++) { - final Object lineObj = this.lines.get(ex + x); - if (lineObj instanceof final ClientDCInternalInv inv) { - for (int z = 0; z < inv.getInventory().getSizeInventory(); z++) { - if (this.matchedStacks.contains(inv.getInventory().getStackInSlot(z))) drawRect( - z * 18 + 22, - 1 + offset, - z * 18 + 22 + 16, - 1 + offset + 16, - GuiColors.InterfaceTerminalMatch.getColor()); - } - } else if (lineObj instanceof String name) { - final int rows = this.byName.get(name).size(); - String postfix = ""; - - if (rows > 1) { - postfix = " (" + rows + ')'; - } - - while (name.length() > 2 && this.fontRendererObj.getStringWidth(name + postfix) > 158) { - name = name.substring(0, name.length() - 1); - } - - this.fontRendererObj.drawString( - name + postfix, - GuiInterfaceTerminalWireless.offsetX + 3, - 6 + offset, - GuiColors.InterfaceTerminalName.getColor()); - } - - offset += 18; - } - } - - @Override - public void drawScreen(final int mouseX, final int mouseY, final float btn) { - - buttonList.clear(); - inventorySlots.inventorySlots.removeIf(slot -> slot instanceof SlotDisconnected); - - guiButtonAssemblersOnly.set( - onlyMolecularAssemblers ? ActionItems.MOLECULAR_ASSEMBLEERS_ON : ActionItems.MOLECULAR_ASSEMBLEERS_OFF); - guiButtonHideFull.set( - AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal - ? ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF - : ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON); - guiButtonBrokenRecipes.set( - onlyBrokenRecipes ? ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERN_OFF - : ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERN_ON); - - terminalStyleBox.set(AEConfig.instance.settings.getSetting(Settings.TERMINAL_STYLE)); - - buttonList.add(guiButtonAssemblersOnly); - buttonList.add(guiButtonHideFull); - buttonList.add(guiButtonBrokenRecipes); - - buttonList.add(terminalStyleBox); - buttonList.add(searchStringSave); - buttonList.add(craftingStatusBtn); - this.guiButtonHashMap.clear(); - addSwitchGuiBtns(); - - int offset = 51; - final int ex = this.getScrollBar().getCurrentScroll(); - for (int x = 0; x < this.rows && ex + x < this.lines.size(); x++) { - final Object lineObj = this.lines.get(ex + x); - if (lineObj instanceof final ClientDCInternalInv inv) { - for (int z = 0; z < inv.getInventory().getSizeInventory(); z++) { - inventorySlots.inventorySlots.add(new SlotDisconnected(inv, z, z * 18 + 22, 1 + offset)); - } - - GuiButton guiButton = new GuiImgButton( - guiLeft + 4, - guiTop + offset + 1, - Settings.ACTIONS, - ActionItems.HIGHLIGHT_INTERFACE); - GuiFCImgButton editButton = new GuiFCImgButton(guiLeft + 4, guiTop + offset + 1, "EDIT", "YES"); - guiButtonHashMap.put(guiButton, inv); - guiButtonHashMap.put(editButton, inv); - if (isShiftKeyDown()) { - buttonList.add(editButton); - } else { - buttonList.add(guiButton); - } - } - - offset += 18; - } - - super.drawScreen(mouseX, mouseY, btn); - - handleTooltip(mouseX, mouseY, searchFieldInputs); - handleTooltip(mouseX, mouseY, searchFieldOutputs); - handleTooltip(mouseX, mouseY, searchFieldNames); - } - - @Override - protected void mouseClicked(final int xCoord, final int yCoord, final int btn) { - boolean focusIn = searchFieldInputs.isFocused(); - boolean focusOut = searchFieldOutputs.isFocused(); - boolean focusName = searchFieldNames.isFocused(); - - searchFieldInputs.mouseClicked(xCoord, yCoord, btn); - searchFieldOutputs.mouseClicked(xCoord, yCoord, btn); - searchFieldNames.mouseClicked(xCoord, yCoord, btn); - - if (focusIn && !searchFieldInputs.isFocused()) { - searchFieldInputsText = searchFieldInputs.getText(); - } else if (focusOut && !searchFieldOutputs.isFocused()) { - searchFieldOutputsText = searchFieldOutputs.getText(); - } else if (focusName && !searchFieldNames.isFocused()) { - searchFieldNamesText = searchFieldNames.getText(); - } - super.mouseClicked(xCoord, yCoord, btn); - } - - @Override - protected void actionPerformed(final GuiButton btn) { - if (guiButtonHashMap.containsKey(btn)) { - Util.DimensionalCoordSide blockPos = blockPosHashMap.get(guiButtonHashMap.get(btn)); - if (btn instanceof GuiFCImgButton) { - FluidCraft.proxy.netHandler.sendToServer( - new CPacketRenamer( - blockPos.x, - blockPos.y, - blockPos.z, - blockPos.getDimension(), - blockPos.getSide())); - } else { - - WorldCoord blockPos2 = new WorldCoord( - (int) mc.thePlayer.posX, - (int) mc.thePlayer.posY, - (int) mc.thePlayer.posZ); - if (mc.theWorld.provider.dimensionId != blockPos.getDimension()) { - mc.thePlayer.addChatMessage( - new ChatComponentTranslation( - PlayerMessages.InterfaceInOtherDim.getName(), - blockPos.getDimension())); - } else { - BlockPosHighlighter.highlightBlock( - blockPos, - System.currentTimeMillis() + 500 * WorldCoord.getTaxicabDistance(blockPos, blockPos2)); - mc.thePlayer.addChatMessage( - new ChatComponentTranslation( - PlayerMessages.InterfaceHighlighted.getName(), - blockPos.x, - blockPos.y, - blockPos.z)); - } - mc.thePlayer.closeScreen(); - } - } else if (btn == guiButtonHideFull) { - AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal = !AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal; - this.refreshList(); - } else if (btn == guiButtonAssemblersOnly) { - onlyMolecularAssemblers = !onlyMolecularAssemblers; - this.refreshList(); - } else if (btn == guiButtonBrokenRecipes) { - onlyBrokenRecipes = !onlyBrokenRecipes; - this.refreshList(); - } else if (ModAndClassUtil.isSaveText && btn == searchStringSave) { - final boolean backwards = Mouse.isButtonDown(1); - final GuiImgButton iBtn = (GuiImgButton) btn; - final Enum cv = iBtn.getCurrentValue(); - final Enum next = Platform.rotateEnum(cv, backwards, iBtn.getSetting().getPossibleValues()); - AEConfig.instance.preserveSearchBar = next == YesNo.YES; - AEConfig.instance.settings.putSetting(Settings.SAVE_SEARCH, next); - this.searchStringSave.set(next); - - } else if (btn == craftingStatusBtn) { - InventoryHandler.switchGui(GuiType.CRAFTING_STATUS); - } else if (btn instanceof final GuiImgButton iBtn) { - if (iBtn.getSetting() != Settings.ACTIONS) { - final Enum cv = iBtn.getCurrentValue(); - final boolean backwards = Mouse.isButtonDown(1); - final Enum next = Platform.rotateEnum(cv, backwards, iBtn.getSetting().getPossibleValues()); - - if (btn == this.terminalStyleBox) { - AEConfig.instance.settings.putSetting(iBtn.getSetting(), next); - - this.reinitialize(); - } - - iBtn.set(next); - } - } - super.actionPerformed(btn); - } - - private void reinitialize() { - this.buttonList.clear(); - this.initGui(); - } - - @Override - public void drawBG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { - this.bindTexture("guis/newinterfaceterminal.png"); - this.drawTexturedModalRect(offsetX, offsetY, 0, 0, this.xSize, 53); - - int offset = 51; - final int ex = this.getScrollBar().getCurrentScroll(); - - for (int x = 0; x < this.rows; x++) { - this.drawTexturedModalRect(offsetX, offsetY + 53 + x * 18, 0, 52, this.xSize, 18); - } - - for (int x = 0; x < this.rows && ex + x < this.lines.size(); x++) { - - final Object lineObj = this.lines.get(ex + x); - if (lineObj instanceof final ClientDCInternalInv inv) { - - GL11.glColor4f(1, 1, 1, 1); - final int width = inv.getInventory().getSizeInventory() * 18; - this.drawTexturedModalRect(offsetX + 20, offsetY + offset, 20, 173, width, 18); - } - - offset += 18; - } - - this.drawTexturedModalRect(offsetX, offsetY + 50 + this.rows * 18, 0, 158, this.xSize, 99); - - searchFieldInputs.drawTextBox(); - searchFieldOutputs.drawTextBox(); - searchFieldNames.drawTextBox(); - } - - @Override - protected void keyTyped(final char character, final int key) { - if (!checkHotbarKeys(key)) { - if (character == ' ') { - if ((searchFieldInputs.getText().isEmpty() && searchFieldInputs.isFocused()) - || (searchFieldOutputs.getText().isEmpty() && searchFieldOutputs.isFocused()) - || (searchFieldNames.getText().isEmpty() && searchFieldNames.isFocused())) - return; - } else if (character == '\t') { - if (handleTab()) return; - } - if (searchFieldInputs.textboxKeyTyped(character, key) || searchFieldOutputs.textboxKeyTyped(character, key) - || searchFieldNames.textboxKeyTyped(character, key)) { - refreshList(); - } else { - super.keyTyped(character, key); - } - } - } - - private boolean handleTab() { - if (searchFieldInputs.isFocused()) { - searchFieldInputs.setFocused(false); - if (isShiftKeyDown()) searchFieldNames.setFocused(true); - else searchFieldOutputs.setFocused(true); - return true; - } else if (searchFieldOutputs.isFocused()) { - searchFieldOutputs.setFocused(false); - if (isShiftKeyDown()) searchFieldInputs.setFocused(true); - else searchFieldNames.setFocused(true); - return true; - } else if (searchFieldNames.isFocused()) { - searchFieldNames.setFocused(false); - if (isShiftKeyDown()) searchFieldOutputs.setFocused(true); - else searchFieldInputs.setFocused(true); - return true; - } - return false; - } - - public void postUpdate(final NBTTagCompound in) { - if (in.getBoolean("clear")) { - this.byId.clear(); - this.refreshList = true; - } - - for (final Object oKey : in.func_150296_c()) { - final String key = (String) oKey; - if (key.startsWith("=")) { - try { - final long id = Long.parseLong(key.substring(1), Character.MAX_RADIX); - final NBTTagCompound invData = in.getCompoundTag(key); - int size = invData.getInteger("size"); - final ClientDCInternalInv current = this - .getById(id, invData.getLong("sortBy"), invData.getString("un"), size); - int X = invData.getInteger("x"); - int Y = invData.getInteger("y"); - int Z = invData.getInteger("z"); - int dim = invData.getInteger("dim"); - ForgeDirection side = ForgeDirection.getOrientation(invData.getInteger("side")); - blockPosHashMap.put( - current, - new Util.DimensionalCoordSide(X, Y, Z, dim, side, current.getUnlocalizedName())); - - for (int x = 0; x < current.getInventory().getSizeInventory(); x++) { - final String which = Integer.toString(x); - if (invData.hasKey(which)) { - current.getInventory().setInventorySlotContents( - x, - ItemStack.loadItemStackFromNBT(invData.getCompoundTag(which))); - } - } - } catch (final NumberFormatException ignored) {} - } - } - - if (this.refreshList) { - this.refreshList = false; - // invalidate caches on refresh - this.cachedSearches.clear(); - this.refreshList(); - } - } - - /** - * Rebuilds the list of interfaces. - *

- * Respects a search term if present (ignores case) and adding only matching patterns. - */ - private void refreshList() { - this.byName.clear(); - this.buttonList.clear(); - this.matchedStacks.clear(); - - final String searchFieldInputs = this.searchFieldInputs.getText().toLowerCase(); - final String searchFieldOutputs = this.searchFieldOutputs.getText().toLowerCase(); - final String searchFieldNames = this.searchFieldNames.getText().toLowerCase(); - - final Set cachedSearch = this.getCacheForSearchTerm( - "IN:" + searchFieldInputs - + "OUT:" - + searchFieldOutputs - + "NAME:" - + searchFieldNames - + AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal - + onlyMolecularAssemblers - + onlyBrokenRecipes); - final boolean rebuild = cachedSearch.isEmpty(); - - for (final ClientDCInternalInv entry : this.byId.values()) { - // ignore inventory if not doing a full rebuild and cache already marks it as miss. - if (!rebuild && !cachedSearch.contains(entry)) { - continue; - } - - // Shortcut to skip any filter if search term is ""/empty - boolean found = searchFieldInputs.isEmpty() && searchFieldOutputs.isEmpty(); - boolean interfaceHasFreeSlots = false; - boolean interfaceHasBrokenRecipes = false; - - // Search if the current inventory holds a pattern containing the search term. - if (!found || AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal || onlyBrokenRecipes) { - for (final ItemStack itemStack : entry.getInventory()) { - // If only Interfaces with empty slots should be shown, check that here - if (itemStack == null) { - interfaceHasFreeSlots = true; - continue; - } - - if (onlyBrokenRecipes && recipeIsBroken(itemStack)) { - interfaceHasBrokenRecipes = true; - } - - if ((!searchFieldInputs.isEmpty() && itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0)) - || (!searchFieldOutputs.isEmpty() - && itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1))) { - found = true; - matchedStacks.add(itemStack); - } - } - } - - if ((found && entry.getName().toLowerCase().contains(searchFieldNames)) - && (!onlyMolecularAssemblers || entry.getUnlocalizedName().contains(MOLECULAR_ASSEMBLER)) - && (!AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal || interfaceHasFreeSlots) - && (!onlyBrokenRecipes || interfaceHasBrokenRecipes)) { - this.byName.put(entry.getName(), entry); - cachedSearch.add(entry); - } else { - cachedSearch.remove(entry); - } - } - - this.names.clear(); - this.names.addAll(this.byName.keySet()); - - Collections.sort(this.names); - - this.lines.clear(); - this.lines.ensureCapacity(this.names.size() + this.byId.size()); - - for (final String n : this.names) { - this.lines.add(n); - final ArrayList clientInventories = new ArrayList<>(this.byName.get(n)); - Collections.sort(clientInventories); - this.lines.addAll(clientInventories); - } - - this.setScrollBar(); - } - - private boolean itemStackMatchesSearchTerm(final ItemStack itemStack, final String searchTerm, int pass) { - if (itemStack == null) { - return false; - } - - final NBTTagCompound encodedValue = itemStack.getTagCompound(); - - if (encodedValue == null) { - return false; - } - - final NBTTagList tags = encodedValue.getTagList(pass == 0 ? "in" : "out", 10); - final boolean containsInvalidDisplayName = GuiText.UnknownItem.getLocal().toLowerCase().contains(searchTerm); - - for (int i = 0; i < tags.tagCount(); i++) { - final NBTTagCompound tag = tags.getCompoundTagAt(i); - final ItemStack parsedItemStack = ItemStack.loadItemStackFromNBT(tag); - - if (parsedItemStack != null) { - final String displayName = Platform - .getItemDisplayName(AEApi.instance().storage().createItemStack(parsedItemStack)).toLowerCase(); - if (displayName.contains(searchTerm)) { - return true; - } - } else if (containsInvalidDisplayName && !tag.hasNoTags()) { - return true; - } - } - - return false; - } - - private boolean recipeIsBroken(final ItemStack itemStack) { - - if (itemStack == null) { - return false; - } - - final NBTTagCompound encodedValue = itemStack.getTagCompound(); - if (encodedValue == null) { - return true; - } - - final World w = CommonHelper.proxy.getWorld(); - if (w == null) { - return false; - } - - try { - new PatternHelper(itemStack, w); - return false; - } catch (final Throwable t) { - return true; - } - } - - /** - * Tries to retrieve a cache for a with search term as keyword. - *

- * If this cache should be empty, it will populate it with an earlier cache if available or at least the cache for - * the empty string. - * - * @param searchTerm the corresponding search - * @return a Set matching a superset of the search term - */ - private Set getCacheForSearchTerm(final String searchTerm) { - if (!this.cachedSearches.containsKey(searchTerm)) { - this.cachedSearches.put(searchTerm, new HashSet<>()); - } - - final Set cache = this.cachedSearches.get(searchTerm); - - if (cache.isEmpty() && searchTerm.length() > 1) { - cache.addAll(this.getCacheForSearchTerm(searchTerm.substring(0, searchTerm.length() - 1))); - return cache; - } - - return cache; - } - - private int getMaxRows() { - return AEConfig.instance.getConfigManager().getSetting(Settings.TERMINAL_STYLE) == TerminalStyle.SMALL - ? AEConfig.instance.InterfaceTerminalSmallSize - : Integer.MAX_VALUE; - } - - private ClientDCInternalInv getById(final long id, final long sortBy, final String unlocalizedName, - final int sizeInit) { - ClientDCInternalInv o = this.byId.get(id); - - if (o == null) { - this.byId.put(id, o = new ClientDCInternalInv(sizeInit, id, sortBy, unlocalizedName)); - this.refreshList = true; - } - - return o; - } - - public boolean isOverTextField(final int mousex, final int mousey) { - return searchFieldInputs.isMouseIn(mousex, mousey) || searchFieldOutputs.isMouseIn(mousex, mousey) - || searchFieldNames.isMouseIn(mousex, mousey); - } - - public void setTextFieldValue(final String displayName, final int mousex, final int mousey, final ItemStack stack) { - - if (searchFieldInputs.isMouseIn(mousex, mousey)) { - searchFieldInputs.setText(displayName); - } else if (searchFieldOutputs.isMouseIn(mousex, mousey)) { - searchFieldOutputs.setText(displayName); - } else if (searchFieldNames.isMouseIn(mousex, mousey)) { - searchFieldNames.setText(displayName); - } - } - -} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiInterfaceWireless.java b/src/main/java/com/glodblock/github/client/gui/GuiInterfaceWireless.java new file mode 100644 index 000000000..b586c87dc --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiInterfaceWireless.java @@ -0,0 +1,1369 @@ +package com.glodblock.github.client.gui; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.base.FCBaseMEGui; +import com.glodblock.github.client.gui.container.ContainerInterfaceWireless; +import com.glodblock.github.inventory.item.IWirelessTerminal; +import com.glodblock.github.network.CPacketRenamer; + +import appeng.api.AEApi; +import appeng.api.config.ActionItems; +import appeng.api.config.Settings; +import appeng.api.config.TerminalStyle; +import appeng.api.util.DimensionalCoord; +import appeng.api.util.WorldCoord; +import appeng.client.gui.IInterfaceTerminalPostUpdate; +import appeng.client.gui.widgets.GuiImgButton; +import appeng.client.gui.widgets.GuiScrollbar; +import appeng.client.gui.widgets.IDropToFillTextField; +import appeng.client.gui.widgets.MEGuiTextField; +import appeng.client.render.BlockPosHighlighter; +import appeng.container.slot.AppEngSlot; +import appeng.core.AEConfig; +import appeng.core.AppEng; +import appeng.core.CommonHelper; +import appeng.core.localization.ButtonToolTips; +import appeng.core.localization.GuiColors; +import appeng.core.localization.GuiText; +import appeng.core.localization.PlayerMessages; +import appeng.core.sync.network.NetworkHandler; +import appeng.core.sync.packets.PacketInterfaceTerminalUpdate; +import appeng.core.sync.packets.PacketInventoryAction; +import appeng.helpers.InventoryAction; +import appeng.helpers.PatternHelper; +import appeng.integration.IntegrationRegistry; +import appeng.integration.IntegrationType; +import appeng.items.misc.ItemEncodedPattern; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.Platform; +import appeng.util.item.AEItemStack; +import cpw.mods.fml.common.Loader; + +public class GuiInterfaceWireless extends FCBaseMEGui implements IDropToFillTextField, IInterfaceTerminalPostUpdate { + + public static final int HEADER_HEIGHT = 52; + public static final int INV_HEIGHT = 98; + public static final int VIEW_WIDTH = 174; + public static final int VIEW_LEFT = 10; + protected static final ResourceLocation BACKGROUND = new ResourceLocation( + AppEng.MOD_ID, + "textures/guis/newinterfaceterminal.png"); + + private final InterfaceWirelessList masterList = new InterfaceWirelessList(); + private final MEGuiTextField searchFieldOutputs; + private final MEGuiTextField searchFieldInputs; + private final MEGuiTextField searchFieldNames; + private final GuiImgButton guiButtonHideFull; + private final GuiImgButton guiButtonAssemblersOnly; + private final GuiImgButton guiButtonBrokenRecipes; + private final GuiImgButton terminalStyleBox; + private boolean onlyMolecularAssemblers = false; + private boolean onlyBrokenRecipes = false; + private boolean online; + /** The height of the viewport. */ + private int viewHeight; + private final List extraOptionsText; + private ItemStack tooltipStack; + private final boolean neiPresent; + /* + * Z-level Map (FLOATS) 0.0 - BACKGROUND 1.0 - ItemStacks 2.0 - Slot color overlays 20.0 - ItemStack overlays 21.0 - + * Slot mouse hover overlay 200.0 - Tooltips + */ + private static final float ITEM_STACK_Z = 100.0f; + private static final float SLOT_Z = 0.5f; + private static final float ITEM_STACK_OVERLAY_Z = 200.0f; + private static final float SLOT_HOVER_Z = 310.0f; + private static final float TOOLTIP_Z = 410.0f; + private static final float STEP_Z = 10.0f; + private static final float MAGIC_RENDER_ITEM_Z = 50.0f; + + protected int offsetY; + + public GuiInterfaceWireless(final InventoryPlayer inventoryPlayer, final IWirelessTerminal te) { + super(inventoryPlayer, new ContainerInterfaceWireless(inventoryPlayer, te)); + + this.setScrollBar(new GuiScrollbar()); + this.xSize = 208; + this.ySize = 255; + this.neiPresent = Loader.isModLoaded("NotEnoughItems"); + + searchFieldInputs = new MEGuiTextField(86, 12, ButtonToolTips.SearchFieldInputs.getLocal()) { + + @Override + public void onTextChange(final String oldText) { + masterList.markDirty(); + } + }; + + searchFieldOutputs = new MEGuiTextField(86, 12, ButtonToolTips.SearchFieldOutputs.getLocal()) { + + @Override + public void onTextChange(final String oldText) { + masterList.markDirty(); + } + }; + + searchFieldNames = new MEGuiTextField(71, 12, ButtonToolTips.SearchFieldNames.getLocal()) { + + @Override + public void onTextChange(final String oldText) { + masterList.markDirty(); + } + }; + searchFieldNames.setFocused(true); + + guiButtonAssemblersOnly = new GuiImgButton(0, 0, Settings.ACTIONS, null); + guiButtonHideFull = new GuiImgButton(0, 0, Settings.ACTIONS, null); + guiButtonBrokenRecipes = new GuiImgButton(0, 0, Settings.ACTIONS, null); + + terminalStyleBox = new GuiImgButton(0, 0, Settings.TERMINAL_STYLE, null); + + this.extraOptionsText = new ArrayList<>(2); + extraOptionsText.add(ButtonToolTips.HighlightInterface.getLocal()); + } + + @Override + public int getOffsetY() { + return this.offsetY; + } + + @Override + public void setOffsetY(int y) { + this.offsetY = y; + } + + private void setScrollBar() { + int maxScroll = this.masterList.getHeight() - this.viewHeight - 1; + if (maxScroll <= 0) { + this.getScrollBar().setTop(52).setLeft(189).setHeight(this.viewHeight).setRange(0, 0, 1); + } else { + this.getScrollBar().setTop(52).setLeft(189).setHeight(this.viewHeight).setRange(0, maxScroll, 12); + } + } + + @SuppressWarnings("unchecked") + @Override + public void initGui() { + super.initGui(); + + this.buttonList.clear(); + this.viewHeight = calculateViewHeight(); + this.ySize = HEADER_HEIGHT + INV_HEIGHT + this.viewHeight; + + final int unusedSpace = this.height - this.ySize; + this.guiTop = (int) Math.floor(unusedSpace / (unusedSpace < 0 ? 3.8f : 2.0f)); + + searchFieldInputs.x = guiLeft + Math.max(32, VIEW_LEFT); + searchFieldInputs.y = guiTop + 25; + + searchFieldOutputs.x = guiLeft + Math.max(32, VIEW_LEFT); + searchFieldOutputs.y = guiTop + 38; + + searchFieldNames.x = guiLeft + Math.max(32, VIEW_LEFT) + 99; + searchFieldNames.y = guiTop + 38; + + terminalStyleBox.xPosition = guiLeft - 18; + terminalStyleBox.yPosition = guiTop + 8; + + guiButtonBrokenRecipes.xPosition = guiLeft - 18; + guiButtonBrokenRecipes.yPosition = terminalStyleBox.yPosition + 18; + + guiButtonHideFull.xPosition = guiLeft - 18; + guiButtonHideFull.yPosition = guiButtonBrokenRecipes.yPosition + 18; + + guiButtonAssemblersOnly.xPosition = guiLeft - 18; + guiButtonAssemblersOnly.yPosition = guiButtonHideFull.yPosition + 18; + + offsetY = guiButtonAssemblersOnly.yPosition + 18; + + this.setScrollBar(); + this.repositionSlots(); + + buttonList.add(guiButtonAssemblersOnly); + buttonList.add(guiButtonHideFull); + buttonList.add(guiButtonBrokenRecipes); + buttonList.add(terminalStyleBox); + initGuiDone(); + addSwitchGuiBtns(); + } + + protected void repositionSlots() { + for (final Object obj : this.inventorySlots.inventorySlots) { + if (obj instanceof final AppEngSlot slot) { + slot.yDisplayPosition = this.ySize + slot.getY() - 78 - 4; + } + } + } + + protected int calculateViewHeight() { + final int maxViewHeight = this.getMaxViewHeight(); + final boolean hasNEI = IntegrationRegistry.INSTANCE.isEnabled(IntegrationType.NEI); + final int NEIPadding = hasNEI ? 22 /* input */ + 18 /* top panel */ : 0; + final int availableSpace = this.height - HEADER_HEIGHT - INV_HEIGHT - NEIPadding; + + // screen should use 95% of the space it can, 5% margins + return Math.min((int) (availableSpace * 0.95), maxViewHeight); + } + + @Override + public void drawFG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { + fontRendererObj.drawString( + getGuiDisplayName(GuiText.InterfaceTerminal.getLocal()), + 8, + 6, + GuiColors.InterfaceTerminalTitle.getColor()); + fontRendererObj.drawString( + GuiText.inventory.getLocal(), + VIEW_LEFT + 2, + this.ySize - 96, + GuiColors.InterfaceTerminalInventory.getColor()); + if (!neiPresent && tooltipStack != null) { + renderToolTip(tooltipStack, mouseX, mouseY); + } + } + + @Override + public void drawScreen(final int mouseX, final int mouseY, final float btn) { + guiButtonAssemblersOnly.set( + onlyMolecularAssemblers ? ActionItems.MOLECULAR_ASSEMBLEERS_ON : ActionItems.MOLECULAR_ASSEMBLEERS_OFF); + guiButtonHideFull.set( + AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal + ? ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF + : ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON); + guiButtonBrokenRecipes.set( + onlyBrokenRecipes ? ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERN_OFF + : ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERN_ON); + + terminalStyleBox.set(AEConfig.instance.settings.getSetting(Settings.TERMINAL_STYLE)); + + super.drawScreen(mouseX, mouseY, btn); + + handleTooltip(mouseX, mouseY, searchFieldInputs); + handleTooltip(mouseX, mouseY, searchFieldOutputs); + handleTooltip(mouseX, mouseY, searchFieldNames); + } + + @Override + protected void mouseClicked(final int xCoord, final int yCoord, final int btn) { + searchFieldInputs.mouseClicked(xCoord, yCoord, btn); + searchFieldOutputs.mouseClicked(xCoord, yCoord, btn); + searchFieldNames.mouseClicked(xCoord, yCoord, btn); + + if (masterList.mouseClicked(xCoord - guiLeft - VIEW_LEFT, yCoord - guiTop - HEADER_HEIGHT, btn)) { + return; + } + super.mouseClicked(xCoord, yCoord, btn); + } + + @Override + protected void actionPerformed(final GuiButton btn) { + if (btn == guiButtonAssemblersOnly) { + onlyMolecularAssemblers = !onlyMolecularAssemblers; + masterList.markDirty(); + } else if (btn == guiButtonHideFull) { + AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal = !AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal; + masterList.markDirty(); + } else if (btn == guiButtonBrokenRecipes) { + onlyBrokenRecipes = !onlyBrokenRecipes; + masterList.markDirty(); + } else if (btn instanceof GuiImgButton iBtn) { + if (iBtn.getSetting() != Settings.ACTIONS) { + final Enum cv = iBtn.getCurrentValue(); + final boolean backwards = Mouse.isButtonDown(1); + final Enum next = Platform.rotateEnum(cv, backwards, iBtn.getSetting().getPossibleValues()); + + if (btn == this.terminalStyleBox) { + AEConfig.instance.settings.putSetting(iBtn.getSetting(), next); + initGui(); + } + + iBtn.set(next); + } + } else { + super.actionPerformed(btn); + } + } + + @Override + public void drawBG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { + this.bindTexture(BACKGROUND); + /* Draws the top part. */ + this.drawTexturedModalRect(offsetX, offsetY, 0, 0, xSize, HEADER_HEIGHT); + /* Draws the middle part. */ + Tessellator.instance.startDrawingQuads(); + addTexturedRectToTesselator( + offsetX, + offsetY + HEADER_HEIGHT, + offsetX + xSize, + offsetY + HEADER_HEIGHT + viewHeight + 1, + 0.0f, + 0.0f, + (HEADER_HEIGHT + InterfaceWirelessSection.TITLE_HEIGHT + 1.0f) / 256.0f, + this.xSize / 256.0f, + (HEADER_HEIGHT + 106.0f) / 256.0f); + Tessellator.instance.draw(); + /* Draw the bottom part */ + this.drawTexturedModalRect(offsetX, offsetY + HEADER_HEIGHT + viewHeight, 0, 158, xSize, INV_HEIGHT); + if (online) { + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + /* (0,0) => viewPort's (0,0) */ + GL11.glPushMatrix(); + GL11.glTranslatef(offsetX + VIEW_LEFT, offsetY + HEADER_HEIGHT, 0); + tooltipStack = null; + masterList.hoveredEntry = null; + drawViewport(mouseX - offsetX - VIEW_LEFT, mouseY - offsetY - HEADER_HEIGHT - 1); + GL11.glPopMatrix(); + GL11.glPopAttrib(); + } + searchFieldInputs.drawTextBox(); + searchFieldOutputs.drawTextBox(); + searchFieldNames.drawTextBox(); + } + + /** + * Draws the viewport area + */ + private void drawViewport(int relMouseX, int relMouseY) { + /* Viewport Magic */ + final int scroll = this.getScrollBar().getCurrentScroll(); + int viewY = -scroll; // current y in viewport coordinates + int entryIdx = 0; + List visibleSections = this.masterList.getVisibleSections(); + + final float guiScaleX = (float) mc.displayWidth / width; + final float guiScaleY = (float) mc.displayHeight / height; + GL11.glScissor( + (int) ((guiLeft + VIEW_LEFT) * guiScaleX), + (int) ((height - (guiTop + HEADER_HEIGHT + viewHeight)) * guiScaleY), + (int) (VIEW_WIDTH * guiScaleX), + (int) (this.viewHeight * guiScaleY)); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + + /* + * Render each section + */ + while (viewY < this.viewHeight && entryIdx < visibleSections.size()) { + InterfaceWirelessSection section = visibleSections.get(entryIdx); + int sectionHeight = section.getHeight(); + + /* Is it viewable/in the viewport at all? */ + if (viewY + sectionHeight < 0) { + entryIdx++; + viewY += sectionHeight; + section.visible = false; + continue; + } + + section.visible = true; + int advanceY = drawSection(section, viewY, relMouseX, relMouseY); + viewY += advanceY; + entryIdx++; + } + } + + /** + * Render the section (if it is visible) + * + * @param section the section to render + * @param viewY current y coordinate relative to gui + * @param relMouseX transformed mouse coords relative to viewport + * @param relMouseY transformed mouse coords relative to viewport + * @return the height of the section rendered in viewport coordinates, max of viewHeight. + */ + private int drawSection(InterfaceWirelessSection section, int viewY, int relMouseX, int relMouseY) { + int title; + int renderY = 0; + final int sectionBottom = viewY + section.getHeight() - 1; + final int fontColor = GuiColors.InterfaceTerminalInventory.getColor(); + /* + * Render title + */ + bindTexture(BACKGROUND); + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z + ITEM_STACK_Z + STEP_Z); + if (sectionBottom > 0 && sectionBottom < InterfaceWirelessSection.TITLE_HEIGHT) { + /* Transition draw */ + title = sectionBottom; + } else if (viewY < 0) { + /* Hidden title draw */ + title = 0; + } else { + /* Normal title draw */ + title = 0; + } + GL11.glTranslatef(0.0f, 0.0f, -(ITEM_STACK_OVERLAY_Z + ITEM_STACK_Z + STEP_Z)); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + Iterator visible = section.getVisible(); + while (visible.hasNext()) { + if (viewY < viewHeight) { + renderY += drawEntry( + visible.next(), + viewY + InterfaceWirelessSection.TITLE_HEIGHT + renderY, + title, + relMouseX, + relMouseY); + } else { + InerfaceWirelessEntry entry = visible.next(); + entry.dispY = -9999; + entry.optionsButton.yPosition = -1; + } + } + bindTexture(BACKGROUND); + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z + ITEM_STACK_Z + STEP_Z); + if (sectionBottom > 0 && sectionBottom < InterfaceWirelessSection.TITLE_HEIGHT) { + /* Transition draw */ + drawTexturedModalRect( + 0, + 0, + VIEW_LEFT, + HEADER_HEIGHT + InterfaceWirelessSection.TITLE_HEIGHT - sectionBottom, + VIEW_WIDTH, + sectionBottom); + fontRendererObj + .drawString(section.name, 2, sectionBottom - InterfaceWirelessSection.TITLE_HEIGHT + 2, fontColor); + } else if (viewY < 0) { + /* Hidden title draw */ + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glTranslatef(0.0f, 0.0f, 100f); + drawTexturedModalRect(0, 0, VIEW_LEFT, HEADER_HEIGHT, VIEW_WIDTH, InterfaceWirelessSection.TITLE_HEIGHT); + fontRendererObj.drawString(section.name, 2, 2, fontColor); + GL11.glEnable(GL11.GL_DEPTH_TEST); + } else { + /* Normal title draw */ + drawTexturedModalRect( + 0, + viewY, + VIEW_LEFT, + HEADER_HEIGHT, + VIEW_WIDTH, + InterfaceWirelessSection.TITLE_HEIGHT); + fontRendererObj.drawString(section.name, 2, viewY + 2, fontColor); + } + GL11.glTranslatef(0.0f, 0.0f, -(ITEM_STACK_OVERLAY_Z + ITEM_STACK_Z + STEP_Z)); + + return InterfaceWirelessSection.TITLE_HEIGHT + renderY; + } + + /** + * Draws the entry. In practice it just draws the slots + items. + * + * @param viewY the gui coordinate z + */ + private int drawEntry(InerfaceWirelessEntry entry, int viewY, int titleBottom, int relMouseX, int relMouseY) { + bindTexture(BACKGROUND); + Tessellator.instance.startDrawingQuads(); + int relY = 0; + final int slotLeftMargin = (VIEW_WIDTH - entry.rowSize * 18); + + entry.dispY = viewY; + /* PASS 1: BG */ + for (int row = 0; row < entry.rows; ++row) { + final int rowYTop = row * 18; + final int rowYBot = rowYTop + 18; + + relY += 18; + /* Is the slot row in view? */ + if (viewY + rowYBot <= titleBottom) { + continue; + } + for (int col = 0; col < entry.rowSize; ++col) { + addTexturedRectToTesselator( + col * 18 + slotLeftMargin, + viewY + rowYTop, + 18 * col + 18 + slotLeftMargin, + viewY + rowYBot, + 0, + 21 / 256f, + 173 / 256f, + (21 + 18) / 256f, + (173 + 18) / 256f); + } + } + Tessellator.instance.draw(); + /* Draw button */ + if (viewY + entry.optionsButton.height > 0 && viewY < viewHeight) { + entry.optionsButton.yPosition = viewY + 5; + entry.renameButton.yPosition = viewY + 5; + GuiFCImgButton toRender; + if (isShiftKeyDown()) { + toRender = entry.renameButton; + } else { + toRender = entry.optionsButton; + } + toRender.drawButton(mc, relMouseX, relMouseY); + if (toRender.getMouseIn() + && relMouseY >= Math.max(InterfaceWirelessSection.TITLE_HEIGHT, entry.optionsButton.yPosition)) { + // draw a tooltip + GL11.glTranslatef(0f, 0f, TOOLTIP_Z); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + drawHoveringText(Arrays.asList(toRender.getMessage()), relMouseX, relMouseY); + GL11.glTranslatef(0f, 0f, -TOOLTIP_Z); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + } + } else { + entry.optionsButton.yPosition = -1; + entry.renameButton.yPosition = -1; + } + /* PASS 2: Items */ + for (int row = 0; row < entry.rows; ++row) { + final int rowYTop = row * 18; + final int rowYBot = rowYTop + 18; + /* Is the slot row in view? */ + if (viewY + rowYBot <= titleBottom) { + continue; + } + AppEngInternalInventory inv = entry.getInventory(); + + for (int col = 0; col < entry.rowSize; ++col) { + final int colLeft = col * 18 + slotLeftMargin + 1; + final int colRight = colLeft + 18 + 1; + final int slotIdx = row * entry.rowSize + col; + ItemStack stack = inv.getStackInSlot(slotIdx); + + boolean tooltip = relMouseX > colLeft - 1 && relMouseX < colRight - 1 + && relMouseY >= Math.max(viewY + rowYTop, InterfaceWirelessSection.TITLE_HEIGHT) + && relMouseY < Math.min(viewY + rowYBot, viewHeight); + if (stack != null) { + final ItemEncodedPattern iep = (ItemEncodedPattern) stack.getItem(); + final ItemStack toRender = iep.getOutput(stack); + + GL11.glPushMatrix(); + GL11.glTranslatef(colLeft, viewY + rowYTop + 1, ITEM_STACK_Z); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + RenderHelper.enableGUIStandardItemLighting(); + translatedRenderItem.zLevel = ITEM_STACK_Z - MAGIC_RENDER_ITEM_Z; + translatedRenderItem + .renderItemAndEffectIntoGUI(fontRendererObj, mc.getTextureManager(), toRender, 0, 0); + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z - ITEM_STACK_Z); + aeRenderItem.setAeStack(AEItemStack.create(toRender)); + aeRenderItem.renderItemOverlayIntoGUI(fontRendererObj, mc.getTextureManager(), toRender, 0, 0); + aeRenderItem.zLevel = 0.0f; + RenderHelper.disableStandardItemLighting(); + if (!tooltip) { + if (entry.brokenRecipes[slotIdx]) { + GL11.glTranslatef(0.0f, 0.0f, SLOT_Z - ITEM_STACK_OVERLAY_Z); + drawRect(0, 0, 16, 16, GuiColors.ItemSlotOverlayInvalid.getColor()); + } else if (entry.filteredRecipes[slotIdx]) { + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z); + drawRect(0, 0, 16, 16, GuiColors.ItemSlotOverlayUnpowered.getColor()); + } + } else { + tooltipStack = stack; + } + GL11.glPopMatrix(); + } else if (entry.filteredRecipes[slotIdx]) { + GL11.glPushMatrix(); + GL11.glTranslatef(colLeft, viewY + rowYTop + 1, ITEM_STACK_OVERLAY_Z); + drawRect(0, 0, 16, 16, GuiColors.ItemSlotOverlayUnpowered.getColor()); + GL11.glPopMatrix(); + } + if (tooltip) { + // overlay highlight + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glTranslatef(0.0f, 0.0f, SLOT_HOVER_Z); + drawRect(colLeft, viewY + 1 + rowYTop, -2 + colRight, viewY - 1 + rowYBot, 0x77FFFFFF); + GL11.glTranslatef(0.0f, 0.0f, -SLOT_HOVER_Z); + masterList.hoveredEntry = entry; + entry.hoveredSlotIdx = slotIdx; + } + GL11.glDisable(GL11.GL_LIGHTING); + } + } + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + return relY + 1; + } + + @Override + public List handleItemTooltip(ItemStack stack, int mouseX, int mouseY, List currentToolTip) { + return currentToolTip; + } + + @Override + public ItemStack getHoveredStack() { + return tooltipStack; + } + + /** + * A copy of super method, but modified to allow for depth testing. + */ + @SuppressWarnings("unchecked") + @Override + public void drawHoveringText(List textLines, int x, int y, FontRenderer font) { + if (!textLines.isEmpty()) { + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + RenderHelper.disableStandardItemLighting(); + int maxStrWidth = 0; + + // is this more efficient than doing 1 pass, then doing a translate before drawing the text? + for (String s : (List) textLines) { + int width = font.getStringWidth(s); + + if (width > maxStrWidth) { + maxStrWidth = width; + } + } + + // top left corner + int curX = x + 12; + int curY = y - 12; + int totalHeight = 8; + + if (textLines.size() > 1) { + totalHeight += 2 + (textLines.size() - 1) * 10; + } + + /* String is too long? Display on the left side */ + if (curX + maxStrWidth > this.width) { + curX -= 28 + maxStrWidth; + } + + /* String is too tall? move it up */ + if (curY + totalHeight + 6 > this.height) { + curY = this.height - totalHeight - 6; + } + + int borderColor = -267386864; + // drawing the border... + this.drawGradientRect(curX - 3, curY - 4, curX + maxStrWidth + 3, curY - 3, borderColor, borderColor); + this.drawGradientRect( + curX - 3, + curY + totalHeight + 3, + curX + maxStrWidth + 3, + curY + totalHeight + 4, + borderColor, + borderColor); + this.drawGradientRect( + curX - 3, + curY - 3, + curX + maxStrWidth + 3, + curY + totalHeight + 3, + borderColor, + borderColor); + this.drawGradientRect(curX - 4, curY - 3, curX - 3, curY + totalHeight + 3, borderColor, borderColor); + this.drawGradientRect( + curX + maxStrWidth + 3, + curY - 3, + curX + maxStrWidth + 4, + curY + totalHeight + 3, + borderColor, + borderColor); + int color1 = 1347420415; + int color2 = (color1 & 16711422) >> 1 | color1 & -16777216; + this.drawGradientRect(curX - 3, curY - 3 + 1, curX - 3 + 1, curY + totalHeight + 3 - 1, color1, color2); + this.drawGradientRect( + curX + maxStrWidth + 2, + curY - 3 + 1, + curX + maxStrWidth + 3, + curY + totalHeight + 3 - 1, + color1, + color2); + this.drawGradientRect(curX - 3, curY - 3, curX + maxStrWidth + 3, curY - 3 + 1, color1, color1); + this.drawGradientRect( + curX - 3, + curY + totalHeight + 2, + curX + maxStrWidth + 3, + curY + totalHeight + 3, + color2, + color2); + + for (int i = 0; i < textLines.size(); ++i) { + String line = (String) textLines.get(i); + font.drawStringWithShadow(line, curX, curY, -1); + + if (i == 0) { + // gap between name and lore text + curY += 2; + } + + curY += 10; + } + + RenderHelper.enableGUIStandardItemLighting(); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } + } + + @Override + protected void keyTyped(final char character, final int key) { + if (!checkHotbarKeys(key)) { + if (character == ' ') { + if ((searchFieldInputs.getText().isEmpty() && searchFieldInputs.isFocused()) + || (searchFieldOutputs.getText().isEmpty() && searchFieldOutputs.isFocused()) + || (searchFieldNames.getText().isEmpty() && searchFieldNames.isFocused())) + return; + } else if (character == '\t' && handleTab()) { + return; + } + if (searchFieldInputs.textboxKeyTyped(character, key) || searchFieldOutputs.textboxKeyTyped(character, key) + || searchFieldNames.textboxKeyTyped(character, key)) { + return; + } + super.keyTyped(character, key); + } + } + + @Override + protected boolean mouseWheelEvent(int mouseX, int mouseY, int wheel) { + boolean isMouseInViewport = isMouseInViewport(mouseX, mouseY); + GuiScrollbar scrollbar = getScrollBar(); + if (isMouseInViewport && isCtrlKeyDown()) { + if (wheel < 0) { + scrollbar.setCurrentScroll(masterList.getHeight()); + } else { + getScrollBar().setCurrentScroll(0); + } + return true; + } else if (isMouseInViewport && isShiftKeyDown()) { + // advance to the next section + return masterList.scrollNextSection(wheel > 0); + } else { + return super.mouseWheelEvent(mouseX, mouseY, wheel); + } + } + + private boolean isMouseInViewport(int mouseX, int mouseY) { + return mouseX > guiLeft + VIEW_LEFT && mouseX < guiLeft + VIEW_LEFT + VIEW_WIDTH + && mouseY > guiTop + HEADER_HEIGHT + && mouseY < guiTop + HEADER_HEIGHT + viewHeight; + } + + private boolean handleTab() { + if (searchFieldInputs.isFocused()) { + searchFieldInputs.setFocused(false); + if (isShiftKeyDown()) searchFieldNames.setFocused(true); + else searchFieldOutputs.setFocused(true); + return true; + } else if (searchFieldOutputs.isFocused()) { + searchFieldOutputs.setFocused(false); + if (isShiftKeyDown()) searchFieldInputs.setFocused(true); + else searchFieldNames.setFocused(true); + return true; + } else if (searchFieldNames.isFocused()) { + searchFieldNames.setFocused(false); + if (isShiftKeyDown()) searchFieldOutputs.setFocused(true); + else searchFieldInputs.setFocused(true); + return true; + } + return false; + } + + public void postUpdate(List updates, int statusFlags) { + if ((statusFlags & PacketInterfaceTerminalUpdate.CLEAR_ALL_BIT) + == PacketInterfaceTerminalUpdate.CLEAR_ALL_BIT) { + /* Should clear all client entries. */ + this.masterList.list.clear(); + } + /* Should indicate disconnected, so the terminal turns dark. */ + this.online = (statusFlags & PacketInterfaceTerminalUpdate.DISCONNECT_BIT) + != PacketInterfaceTerminalUpdate.DISCONNECT_BIT; + + for (PacketInterfaceTerminalUpdate.PacketEntry cmd : updates) { + parsePacketCmd(cmd); + } + this.masterList.markDirty(); + + } + + private void parsePacketCmd(PacketInterfaceTerminalUpdate.PacketEntry cmd) { + long id = cmd.entryId; + if (cmd instanceof PacketInterfaceTerminalUpdate.PacketAdd addCmd) { + InerfaceWirelessEntry entry = new InerfaceWirelessEntry( + id, + addCmd.name, + addCmd.rows, + addCmd.rowSize, + addCmd.online).setLocation(addCmd.x, addCmd.y, addCmd.z, addCmd.dim, addCmd.side) + .setIcons(addCmd.selfRep, addCmd.dispRep).setItems(addCmd.items); + masterList.addEntry(entry); + } else if (cmd instanceof PacketInterfaceTerminalUpdate.PacketRemove) { + masterList.removeEntry(id); + } else if (cmd instanceof PacketInterfaceTerminalUpdate.PacketOverwrite owCmd) { + InerfaceWirelessEntry entry = masterList.list.get(id); + + if (entry == null) { + return; + } + + if (owCmd.onlineValid) { + entry.online = owCmd.online; + } + + if (owCmd.itemsValid) { + if (owCmd.allItemUpdate) { + entry.fullItemUpdate(owCmd.items, owCmd.validIndices.length); + } else { + entry.partialItemUpdate(owCmd.items, owCmd.validIndices); + } + } + masterList.isDirty = true; + } else if (cmd instanceof PacketInterfaceTerminalUpdate.PacketRename renameCmd) { + InerfaceWirelessEntry entry = masterList.list.get(id); + + if (entry != null) { + if (StatCollector.canTranslate(renameCmd.newName)) { + entry.dispName = StatCollector.translateToLocal(renameCmd.newName); + } else { + entry.dispName = StatCollector.translateToFallback(renameCmd.newName); + } + } + masterList.isDirty = true; + } + } + + private boolean itemStackMatchesSearchTerm(final ItemStack itemStack, final String searchTerm, boolean in) { + if (itemStack == null) { + return false; + } + + final NBTTagCompound encodedValue = itemStack.getTagCompound(); + + if (encodedValue == null) { + return false; + } + + final NBTTagList tags = encodedValue.getTagList(in ? "in" : "out", Constants.NBT.TAG_COMPOUND); + final boolean containsInvalidDisplayName = GuiText.UnknownItem.getLocal().toLowerCase().contains(searchTerm); + + for (int i = 0; i < tags.tagCount(); i++) { + final NBTTagCompound tag = tags.getCompoundTagAt(i); + final ItemStack parsedItemStack = ItemStack.loadItemStackFromNBT(tag); + + if (parsedItemStack != null) { + final String displayName = Platform + .getItemDisplayName(AEApi.instance().storage().createItemStack(parsedItemStack)).toLowerCase(); + if (displayName.contains(searchTerm)) { + return true; + } + } else if (containsInvalidDisplayName && !tag.hasNoTags()) { + return true; + } + } + + return false; + + } + + private boolean recipeIsBroken(final ItemStack itemStack) { + if (itemStack == null) { + return false; + } + + final NBTTagCompound encodedValue = itemStack.getTagCompound(); + if (encodedValue == null) { + return true; + } + + final World w = CommonHelper.proxy.getWorld(); + if (w == null) { + return false; + } + + try { + new PatternHelper(itemStack, w); + return false; + } catch (final Throwable t) { + return true; + } + } + + private int getMaxViewHeight() { + return AEConfig.instance.getConfigManager().getSetting(Settings.TERMINAL_STYLE) == TerminalStyle.SMALL + ? AEConfig.instance.InterfaceTerminalSmallSize * 18 + : Integer.MAX_VALUE; + } + + public boolean isOverTextField(final int mousex, final int mousey) { + return searchFieldInputs.isMouseIn(mousex, mousey) || searchFieldOutputs.isMouseIn(mousex, mousey) + || searchFieldNames.isMouseIn(mousex, mousey); + } + + public void setTextFieldValue(final String displayName, final int mousex, final int mousey, final ItemStack stack) { + if (searchFieldInputs.isMouseIn(mousex, mousey)) { + searchFieldInputs.setText(displayName); + } else if (searchFieldOutputs.isMouseIn(mousex, mousey)) { + searchFieldOutputs.setText(displayName); + } else if (searchFieldNames.isMouseIn(mousex, mousey)) { + searchFieldNames.setText(displayName); + } + } + + /** + * Tracks the list of entries. + */ + private class InterfaceWirelessList { + + private final Map list = new HashMap<>(); + private final Map sections = new TreeMap<>(); + private final List visibleSections = new ArrayList<>(); + private boolean isDirty; + private int height; + private InerfaceWirelessEntry hoveredEntry; + + InterfaceWirelessList() { + this.isDirty = true; + } + + /** + * Performs a full update. + */ + private void update() { + height = 0; + visibleSections.clear(); + + for (InterfaceWirelessSection section : sections.values()) { + String query = GuiInterfaceWireless.this.searchFieldNames.getText(); + if (!query.isEmpty() && !section.name.toLowerCase().contains(query.toLowerCase())) { + continue; + } + + section.isDirty = true; + if (section.getVisible().hasNext()) { + height += section.getHeight(); + visibleSections.add(section); + } + } + isDirty = false; + } + + public void markDirty() { + this.isDirty = true; + setScrollBar(); + } + + public int getHeight() { + if (isDirty) { + update(); + } + return height; + } + + /** + * Jump between sections. + */ + private boolean scrollNextSection(boolean up) { + GuiScrollbar scrollbar = getScrollBar(); + int viewY = scrollbar.getCurrentScroll(); + var sections = getVisibleSections(); + boolean result = false; + + if (up) { + int y = masterList.getHeight(); + int i = sections.size() - 1; + + while (y > 0 && i >= 0) { + y -= sections.get(i).getHeight(); + i -= 1; + if (y < viewY) { + result = true; + scrollbar.setCurrentScroll(y); + break; + } + } + } else { + int y = 0; + + for (InterfaceWirelessSection section : sections) { + if (y > viewY) { + result = true; + scrollbar.setCurrentScroll(y); + break; + } + y += section.getHeight(); + } + } + return result; + } + + public void addEntry(InerfaceWirelessEntry entry) { + InterfaceWirelessSection section = sections.get(entry.dispName); + + if (section == null) { + section = new InterfaceWirelessSection(entry.dispName); + sections.put(entry.dispName, section); + } + section.addEntry(entry); + list.put(entry.id, entry); + isDirty = true; + } + + public void removeEntry(long id) { + InerfaceWirelessEntry entry = list.remove(id); + + if (entry != null) { + entry.section.removeEntry(entry); + } + } + + public List getVisibleSections() { + if (isDirty) { + update(); + } + return visibleSections; + } + + /** + * Mouse button click. + * + * @param relMouseX viewport coords mouse X + * @param relMouseY viewport coords mouse Y + * @param btn button code + */ + public boolean mouseClicked(int relMouseX, int relMouseY, int btn) { + if (relMouseX < 0 || relMouseX >= VIEW_WIDTH || relMouseY < 0 || relMouseY >= viewHeight) { + return false; + } + for (InterfaceWirelessSection section : getVisibleSections()) { + if (section.mouseClicked(relMouseX, relMouseY, btn)) { + return true; + } + } + return false; + } + } + + /** + * A section holds all the interface entries with the same name. + */ + private class InterfaceWirelessSection { + + public static final int TITLE_HEIGHT = 12; + + String name; + List entries = new ArrayList<>(); + Set visibleEntries = new TreeSet<>(Comparator.comparing(e -> { + if (e.dispRep != null) { + return e.dispRep.getDisplayName() + e.id; + } else { + return String.valueOf(e.id); + } + })); + int height; + private boolean isDirty = true; + boolean visible = false; + + InterfaceWirelessSection(String name) { + this.name = name; + } + + /** + * Gets the height. Includes title. + */ + public int getHeight() { + if (isDirty) { + update(); + } + return height; + } + + private void update() { + refreshVisible(); + if (visibleEntries.isEmpty()) { + height = 0; + } else { + height = TITLE_HEIGHT; + for (InerfaceWirelessEntry entry : visibleEntries) { + height += entry.guiHeight; + } + } + isDirty = false; + } + + public void refreshVisible() { + visibleEntries.clear(); + String input = GuiInterfaceWireless.this.searchFieldInputs.getText().toLowerCase(); + String output = GuiInterfaceWireless.this.searchFieldOutputs.getText().toLowerCase(); + + for (InerfaceWirelessEntry entry : entries) { + var moleAss = AEApi.instance().definitions().blocks().molecularAssembler().maybeStack(1); + entry.dispY = -9999; + if (onlyMolecularAssemblers + && (!moleAss.isPresent() || !Platform.isSameItem(moleAss.get(), entry.dispRep))) { + continue; + } + if (AEConfig.instance.showOnlyInterfacesWithFreeSlotsInInterfaceTerminal + && entry.numItems == entry.rows * entry.rowSize) { + continue; + } + if (onlyBrokenRecipes && entry.numBrokenRecipes == 0) { + continue; + } + // Find search terms + if (!input.isEmpty() || !output.isEmpty()) { + AppEngInternalInventory inv = entry.inv; + boolean shouldAdd = false; + + for (int i = 0; i < inv.getSizeInventory(); ++i) { + ItemStack stack = inv.getStackInSlot(i); + if (itemStackMatchesSearchTerm(stack, input, true) + && itemStackMatchesSearchTerm(stack, output, false)) { + shouldAdd = true; + entry.filteredRecipes[i] = false; + } else { + entry.filteredRecipes[i] = true; + } + } + if (!shouldAdd) { + continue; + } + } else { + Arrays.fill(entry.filteredRecipes, false); + } + visibleEntries.add(entry); + } + } + + public void addEntry(InerfaceWirelessEntry entry) { + this.entries.add(entry); + entry.section = this; + this.isDirty = true; + } + + public void removeEntry(InerfaceWirelessEntry entry) { + this.entries.remove(entry); + entry.section = null; + this.isDirty = true; + } + + public Iterator getVisible() { + if (isDirty) { + update(); + } + return visibleEntries.iterator(); + } + + public boolean mouseClicked(int relMouseX, int relMouseY, int btn) { + Iterator it = getVisible(); + boolean ret = false; + + while (it.hasNext() && !ret) { + ret = it.next().mouseClicked(relMouseX, relMouseY, btn); + } + + return ret; + } + } + + /** + * This class keeps track of an entry and its widgets. + */ + private class InerfaceWirelessEntry { + + String dispName; + AppEngInternalInventory inv; + GuiFCImgButton optionsButton; + GuiFCImgButton renameButton; + + /** Nullable - icon that represents the interface */ + ItemStack selfRep; + /** Nullable - icon that represents the interface's "target" */ + ItemStack dispRep; + InterfaceWirelessSection section; + long id; + int x, y, z, dim, side; + int rows, rowSize; + int guiHeight; + int dispY = -9999; + boolean online; + int numBrokenRecipes; + boolean[] brokenRecipes; + int numItems = 0; + /** Should recipe be filtered out/grayed out? */ + boolean[] filteredRecipes; + private int hoveredSlotIdx = -1; + + InerfaceWirelessEntry(long id, String name, int rows, int rowSize, boolean online) { + this.id = id; + if (StatCollector.canTranslate(name)) { + this.dispName = StatCollector.translateToLocal(name); + } else { + String fallback = name + ".name"; // its whatever. save some bytes on network but looks ugly + if (StatCollector.canTranslate(fallback)) { + this.dispName = StatCollector.translateToLocal(fallback); + } else { + this.dispName = StatCollector.translateToFallback(name); + } + } + this.inv = new AppEngInternalInventory(null, rows * rowSize, 1); + this.rows = rows; + this.rowSize = rowSize; + this.online = online; + this.optionsButton = new GuiFCImgButton(2, 0, "HIGHLIGHT", "YES"); + this.optionsButton.setHalfSize(true); + this.renameButton = new GuiFCImgButton(2, 0, "EDIT", "YES"); + this.renameButton.setHalfSize(true); + this.guiHeight = 18 * rows + 1; + this.brokenRecipes = new boolean[rows * rowSize]; + this.filteredRecipes = new boolean[rows * rowSize]; + } + + InerfaceWirelessEntry setLocation(int x, int y, int z, int dim, int side) { + this.x = x; + this.y = y; + this.z = z; + this.dim = dim; + this.side = side; + + return this; + } + + InerfaceWirelessEntry setIcons(ItemStack selfRep, ItemStack dispRep) { + // Kotlin would make this pretty easy :( + this.selfRep = selfRep; + this.dispRep = dispRep; + + return this; + } + + public void fullItemUpdate(NBTTagList items, int newSize) { + inv = new AppEngInternalInventory(null, newSize); + rows = newSize / rowSize; + brokenRecipes = new boolean[newSize]; + numItems = 0; + + for (int i = 0; i < inv.getSizeInventory(); ++i) { + setItemInSlot(ItemStack.loadItemStackFromNBT(items.getCompoundTagAt(i)), i); + } + this.guiHeight = 18 * rows + 4; + } + + InerfaceWirelessEntry setItems(NBTTagList items) { + assert items.tagCount() == inv.getSizeInventory(); + + for (int i = 0; i < items.tagCount(); ++i) { + setItemInSlot(ItemStack.loadItemStackFromNBT(items.getCompoundTagAt(i)), i); + } + return this; + } + + public void partialItemUpdate(NBTTagList items, int[] validIndices) { + for (int i = 0; i < validIndices.length; ++i) { + setItemInSlot(ItemStack.loadItemStackFromNBT(items.getCompoundTagAt(i)), validIndices[i]); + } + } + + private void setItemInSlot(ItemStack stack, int idx) { + final int oldBroke = brokenRecipes[idx] ? 1 : 0; + final int newBroke = recipeIsBroken(stack) ? 1 : 0; + final int oldHasItem = inv.getStackInSlot(idx) != null ? 1 : 0; + final int newHasItem = stack != null ? 1 : 0; + + // Update broken recipe count + numBrokenRecipes += newBroke - oldBroke; + brokenRecipes[idx] = newBroke == 1; + inv.setInventorySlotContents(idx, stack); + assert numBrokenRecipes >= 0; + // Update item count + numItems += newHasItem - oldHasItem; + assert numItems >= 0; + } + + public AppEngInternalInventory getInventory() { + return inv; + } + + public boolean mouseClicked(int mouseX, int mouseY, int btn) { + if (!section.visible || btn < 0 || btn > 2) { + return false; + } + if (mouseX >= optionsButton.xPosition && mouseX < 2 + optionsButton.width + && mouseY > Math.max(optionsButton.yPosition, InterfaceWirelessSection.TITLE_HEIGHT) + && mouseY <= Math.min(optionsButton.yPosition + optionsButton.height, viewHeight)) { + optionsButton.func_146113_a(mc.getSoundHandler()); + DimensionalCoord blockPos = new DimensionalCoord(x, y, z, dim); + + if (isShiftKeyDown()) { + FluidCraft.proxy.netHandler.sendToServer( + new CPacketRenamer( + blockPos.x, + blockPos.y, + blockPos.z, + blockPos.getDimension(), + ForgeDirection.getOrientation(side))); + } else { + /* View in world */ + WorldCoord blockPos2 = new WorldCoord( + (int) mc.thePlayer.posX, + (int) mc.thePlayer.posY, + (int) mc.thePlayer.posZ); + if (mc.theWorld.provider.dimensionId != dim) { + mc.thePlayer.addChatMessage( + new ChatComponentTranslation(PlayerMessages.InterfaceInOtherDim.getName(), dim)); + } else { + BlockPosHighlighter.highlightBlock( + blockPos, + System.currentTimeMillis() + 500 * WorldCoord.getTaxicabDistance(blockPos, blockPos2)); + mc.thePlayer.addChatMessage( + new ChatComponentTranslation( + PlayerMessages.InterfaceHighlighted.getName(), + blockPos.x, + blockPos.y, + blockPos.z)); + } + mc.thePlayer.closeScreen(); + } + return true; + } + + int offsetY = mouseY - dispY; + int offsetX = mouseX - (VIEW_WIDTH - rowSize * 18) - 1; + if (offsetX >= 0 && offsetX < (rowSize * 18) + && mouseY > Math.max(dispY, InterfaceWirelessSection.TITLE_HEIGHT) + && offsetY < Math.min(viewHeight - dispY, guiHeight)) { + final int col = offsetX / 18; + final int row = offsetY / 18; + final int slotIdx = row * rowSize + col; + + // send packet to server, request an update + // TODO: Client prediction. + PacketInventoryAction packet; + + if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)) { + packet = new PacketInventoryAction(InventoryAction.MOVE_REGION, 0, id); + } else if (isShiftKeyDown() && (btn == 0 || btn == 1)) { + packet = new PacketInventoryAction(InventoryAction.SHIFT_CLICK, slotIdx, id); + } else if (btn == 0 || btn == 1) { + packet = new PacketInventoryAction(InventoryAction.PICKUP_OR_SET_DOWN, slotIdx, id); + } else { + packet = new PacketInventoryAction(InventoryAction.CREATIVE_DUPLICATE, slotIdx, id); + } + NetworkHandler.instance.sendToServer(packet); + return true; + } + + return false; + } + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java b/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java index 5f37fc5fc..fb290f8a0 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiLevelMaintainer.java @@ -1,5 +1,7 @@ package com.glodblock.github.client.gui; +import static com.glodblock.github.client.gui.container.ContainerLevelMaintainer.createLevelValues; + import java.awt.Rectangle; import java.util.ArrayList; import java.util.Collections; @@ -13,23 +15,41 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.util.ForgeDirection; import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.ContainerLevelMaintainer; +import com.glodblock.github.common.item.ItemWirelessUltraTerminal; +import com.glodblock.github.common.parts.PartLevelTerminal; import com.glodblock.github.common.tile.TileLevelMaintainer; +import com.glodblock.github.common.tile.TileLevelMaintainer.State; +import com.glodblock.github.common.tile.TileLevelMaintainer.TLMTags; +import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.gui.MouseRegionManager; +import com.glodblock.github.inventory.item.IWirelessTerminal; +import com.glodblock.github.inventory.item.WirelessLevelTerminalInventory; import com.glodblock.github.inventory.slot.SlotFluidConvertingFake; import com.glodblock.github.inventory.slot.SlotSingleItem; +import com.glodblock.github.loader.ItemAndBlockHolder; import com.glodblock.github.network.CPacketLevelMaintainer; -import com.glodblock.github.util.Ae2ReflectClient; +import com.glodblock.github.network.CPacketLevelMaintainer.Action; +import com.glodblock.github.network.CPacketLevelTerminalCommands; +import com.glodblock.github.util.FCGuiColors; import com.glodblock.github.util.NameConst; +import com.glodblock.github.util.Util; import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.DimensionalCoord; import appeng.client.gui.AEBaseGui; -import appeng.client.render.AppEngRenderItem; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.container.AEBaseContainer; import appeng.container.slot.SlotFake; +import appeng.core.AEConfig; +import appeng.core.AELog; +import appeng.core.features.AEFeature; import appeng.core.sync.network.NetworkHandler; import appeng.core.sync.packets.PacketNEIDragClick; import codechicken.nei.VisiblityData; @@ -45,11 +65,15 @@ public class GuiLevelMaintainer extends AEBaseGui implements INEIGuiHandler { private final ContainerLevelMaintainer cont; private final Component[] component = new Component[TileLevelMaintainer.REQ_COUNT]; private final MouseRegionManager mouseRegions = new MouseRegionManager(this); - private final AppEngRenderItem stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); private FCGuiTextField input; private int lastWorkingTick; private int refreshTick; private final CoFHFontRenderer render; + protected ItemStack icon = null; + + protected GuiType originalGui; + protected Util.DimensionalCoordSide originalBlockPos; + protected GuiTabButton originalGuiBtn; public GuiLevelMaintainer(InventoryPlayer ipl, TileLevelMaintainer tile) { super(new ContainerLevelMaintainer(ipl, tile)); @@ -62,27 +86,72 @@ public GuiLevelMaintainer(InventoryPlayer ipl, TileLevelMaintainer tile) { Minecraft.getMinecraft().getTextureManager(), true); this.refreshTick = 0; + if (ipl.player.openContainer instanceof AEBaseContainer container) { + var target = container.getTarget(); + if (target instanceof PartLevelTerminal terminal) { + icon = ItemAndBlockHolder.LEVEL_TERMINAL.stack(); + originalGui = GuiType.LEVEL_TERMINAL; + DimensionalCoord blockPos = new DimensionalCoord(terminal.getTile()); + originalBlockPos = new Util.DimensionalCoordSide( + blockPos.x, + blockPos.y, + blockPos.z, + blockPos.getDimension(), + terminal.getSide(), + ""); + } else if (target instanceof IWirelessTerminal terminal && terminal.isUniversal(target)) { + icon = ItemAndBlockHolder.WIRELESS_ULTRA_TERM.stack(); + originalGui = ItemWirelessUltraTerminal.readMode(terminal.getItemStack()); + originalBlockPos = new Util.DimensionalCoordSide( + terminal.getInventorySlot(), + Util.GuiHelper.encodeType(0, Util.GuiHelper.GuiType.ITEM), + 0, + ipl.player.worldObj.provider.dimensionId, + ForgeDirection.UNKNOWN, + ""); + } else if (target instanceof WirelessLevelTerminalInventory terminal) { + icon = ItemAndBlockHolder.LEVEL_TERMINAL.stack(); + originalGui = GuiType.WIRELESS_LEVEL_TERMINAL; + originalBlockPos = new Util.DimensionalCoordSide( + terminal.getInventorySlot(), + Util.GuiHelper.encodeType(0, Util.GuiHelper.GuiType.ITEM), + 0, + ipl.player.worldObj.provider.dimensionId, + ForgeDirection.UNKNOWN, + ""); + + } + } + } public void postUpdate(List list) { for (Slot slot : this.cont.getRequestSlots()) { if (!slot.getHasStack()) { - component[slot.getSlotIndex()].setState(TileLevelMaintainer.State.Nothing); + component[slot.getSlotIndex()].setState(State.None); } } for (IAEItemStack is : list) { NBTTagCompound data = is.getItemStack().getTagCompound(); - long size = data.getLong("Batch"); - int i = data.getInteger("Index"); - boolean isEnable = data.getBoolean("Enable"); - TileLevelMaintainer.State state = TileLevelMaintainer.State.values()[data.getInteger("State")]; - component[i].getQty().textField.setText(String.valueOf(is.getStackSize())); - component[i].getBatch().textField.setText(String.valueOf(size)); - component[i].setEnable(isEnable); - component[i].setState(state); + if (data == null) { + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info("Received empty configuration: ", is); + } + continue; + } + long batch = data.getLong(TLMTags.Batch.tagName); + long quantity = data.getLong(TLMTags.Quantity.tagName); + int idx = data.getInteger(TLMTags.Index.tagName); + boolean isEnable = data.getBoolean(TLMTags.Enable.tagName); + State state = State.values()[data.getInteger(TLMTags.State.tagName)]; + component[idx].getQty().textField.setText(String.valueOf(quantity)); + component[idx].getBatch().textField.setText(String.valueOf(batch)); + component[idx].setEnable(isEnable); + component[idx].setState(state); } } + @SuppressWarnings("unchecked") public void initGui() { super.initGui(); this.lastWorkingTick = this.refreshTick; @@ -92,19 +161,29 @@ public void initGui() { new FCGuiTextField(this.fontRendererObj, guiLeft + 46, guiTop + 19 + 19 * i, 52, 14), NameConst.TT_LEVEL_MAINTAINER_REQUEST_SIZE, i, - "TileLevelMaintainer.Quantity"), + Action.Quantity), new Widget( new FCGuiTextField(this.fontRendererObj, guiLeft + 100, guiTop + 19 + 19 * i, 52, 14), NameConst.TT_LEVEL_MAINTAINER_BATCH_SIZE, i, - "TileLevelMaintainer.Batch"), + Action.Batch), new GuiFCImgButton(guiLeft + 105 + 47, guiTop + 17 + 19 * i, "SUBMIT", "SUBMIT", false), new GuiFCImgButton(guiLeft + 9, guiTop + 20 + 19 * i, "ENABLE", "ENABLE", false), new GuiFCImgButton(guiLeft + 9, guiTop + 20 + 19 * i, "DISABLE", "DISABLE", false), new FCGuiLineField(fontRendererObj, guiLeft + 47, guiTop + 33 + 19 * i, 125), this.buttonList); } - FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer("TileLevelMaintainer.refresh")); + if (this.icon != null) { + this.originalGuiBtn = new GuiTabButton( + this.guiLeft + 151, + this.guiTop - 4, + this.icon, + this.icon.getDisplayName(), + itemRender); + this.originalGuiBtn.setHideEdge(13); + this.buttonList.add(originalGuiBtn); + } + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer(Action.Refresh)); } public void drawScreen(final int mouseX, final int mouseY, final float btn) { @@ -124,7 +203,7 @@ public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { int tick = this.refreshTick; int interval = 20; if (tick > lastWorkingTick + interval && this.input == null) { - FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer("TileLevelMaintainer.refresh")); + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer(Action.Refresh)); lastWorkingTick = this.refreshTick; } for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { @@ -154,13 +233,15 @@ public boolean drawSlot0(Slot slot) { } else { fake.setStackSize(0); } - stackSizeRenderer.setAeStack(fake); - stackSizeRenderer.renderItemOverlayIntoGUI( + GL11.glTranslatef(0.0f, 0.0f, 200.0f); + aeRenderItem.setAeStack(fake); + aeRenderItem.renderItemOverlayIntoGUI( fontRendererObj, mc.getTextureManager(), - stack.getItemStack(), + fake.getItemStack(), slot.xDisplayPosition, slot.yDisplayPosition); + GL11.glTranslatef(0.0f, 0.0f, -200.0f); return false; } return true; @@ -225,14 +306,33 @@ public void updateAmount(int idx, int stackSize) { @Override protected void actionPerformed(final GuiButton btn) { - super.actionPerformed(btn); - for (Component com : this.component) { - if (com.sendToServer(btn)) { - break; + if (btn == originalGuiBtn) { + switchGui(); + } else { + super.actionPerformed(btn); + for (Component com : this.component) { + if (com.sendToServer(btn)) { + break; + } } } } + public GuiType getOriginalGui() { + return originalGui; + } + + public void switchGui() { + FluidCraft.proxy.netHandler.sendToServer( + new CPacketLevelTerminalCommands( + CPacketLevelTerminalCommands.Action.BACK, + originalBlockPos.x, + originalBlockPos.y, + originalBlockPos.z, + originalBlockPos.getDimension(), + originalBlockPos.getSide())); + } + @Override public VisiblityData modifyVisiblity(GuiContainer gui, VisiblityData currentVisibility) { return currentVisibility; @@ -254,20 +354,20 @@ private Rectangle getSlotArea(SlotFake slot) { @Override public boolean handleDragNDrop(GuiContainer gui, int mouseX, int mouseY, ItemStack draggedStack, int button) { - for (SlotFluidConvertingFake slot : this.cont.getRequestSlots()) { - if (getSlotArea(slot).contains(mouseX, mouseY)) { - slot.putStack(draggedStack); - NetworkHandler.instance.sendToServer(new PacketNEIDragClick(draggedStack, slot.getSlotIndex())); - if (draggedStack != null) { - this.updateAmount(slot.getSlotIndex(), draggedStack.stackSize); - draggedStack.stackSize = 0; - } - return true; - } - } if (draggedStack != null) { draggedStack.stackSize = 0; } + for (int i = 0; i < this.cont.getRequestSlots().length; i++) { + SlotFluidConvertingFake slot = this.cont.getRequestSlots()[i]; + if (getSlotArea(slot).contains(mouseX, mouseY) && draggedStack != null) { + ItemStack itemStack = createLevelValues(draggedStack.copy()); + itemStack.getTagCompound().setInteger(TLMTags.Index.tagName, i); + slot.putStack(itemStack); + NetworkHandler.instance.sendToServer(new PacketNEIDragClick(itemStack, slot.getSlotIndex())); + this.updateAmount(slot.getSlotIndex(), itemStack.stackSize); + return true; + } + } return false; } @@ -285,8 +385,9 @@ private class Component { private final GuiFCImgButton enable; private final GuiFCImgButton submit; private final FCGuiLineField line; - private TileLevelMaintainer.State state; + private State state; + @SuppressWarnings("unchecked") public Component(Widget qtyInput, Widget batchInput, GuiFCImgButton submitBtn, GuiFCImgButton enableBtn, GuiFCImgButton disableBtn, FCGuiLineField line, List buttonList) { this.qty = qtyInput; @@ -295,14 +396,14 @@ public Component(Widget qtyInput, Widget batchInput, GuiFCImgButton submitBtn, G this.disable = disableBtn; this.submit = submitBtn; this.line = line; - this.state = TileLevelMaintainer.State.Nothing; + this.state = State.None; buttonList.add(this.submit); buttonList.add(this.enable); buttonList.add(this.disable); } public int getIndex() { - return this.getQty().idx; + return this.qty.idx; } public void setEnable(boolean enable) { @@ -332,20 +433,18 @@ protected boolean sendToServer(GuiButton btn) { if (this.send(this.getQty())) this.send(this.getBatch()); didSomething = true; } else if (this.enable == btn) { - FluidCraft.proxy.netHandler - .sendToServer(new CPacketLevelMaintainer("TileLevelMaintainer.Enable", this.getIndex())); + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer(Action.Enable, this.getIndex())); didSomething = true; } else if (this.disable == btn) { - FluidCraft.proxy.netHandler - .sendToServer(new CPacketLevelMaintainer("TileLevelMaintainer.Disable", this.getIndex())); + FluidCraft.proxy.netHandler.sendToServer(new CPacketLevelMaintainer(Action.Disable, this.getIndex())); didSomething = true; } return didSomething; } public FCGuiTextField isMouseIn(final int xCoord, final int yCoord) { - if (this.getQty().textField.isMouseIn(xCoord, yCoord)) return this.getQty().textField; - if (this.getBatch().textField.isMouseIn(xCoord, yCoord)) return this.getBatch().textField; + if (this.qty.textField.isMouseIn(xCoord, yCoord)) return this.getQty().textField; + if (this.batch.textField.isMouseIn(xCoord, yCoord)) return this.getBatch().textField; return null; } @@ -362,33 +461,39 @@ public FCGuiLineField getLine() { } public void draw() { - this.getQty().draw(); - this.getBatch().draw(); + this.qty.draw(); + this.batch.draw(); ArrayList message = new ArrayList<>(); message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_TITLE) + "\n"); switch (this.state) { - case Idling -> { - this.line.setColor(0xFF55FF55); + case Idle -> { + this.line.setColor(FCGuiColors.StateIdle.getColor()); message.add( - NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + " " + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_IDLE)); } - case Crafting -> { - this.line.setColor(0xFFFFFF55); + case Craft -> { + this.line.setColor(FCGuiColors.StateCraft.getColor()); message.add( - NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + " " + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_LINK)); } - case Exporting -> { - this.line.setColor(0xFFAA00AA); + case Export -> { + this.line.setColor(FCGuiColors.StateExport.getColor()); message.add( - NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + " " + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_EXPORT)); } + case Error -> { + this.line.setColor(FCGuiColors.StateError.getColor()); + message.add( + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + " " + + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_ERROR)); + } default -> { - this.line.setColor(0); + this.line.setColor(FCGuiColors.StateNone.getColor()); message.add( - NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_CURRENT) + " " + NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_NONE)); } } @@ -399,7 +504,9 @@ public void draw() { message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_LINK)); message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_LINK_DESC) + "\n"); message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_EXPORT)); - message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_EXPORT_DESC)); + message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_EXPORT_DESC) + "\n"); + message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_ERROR)); + message.add(NameConst.i18n(NameConst.TT_LEVEL_MAINTAINER_ERROR_DESC)); } else { message.add(NameConst.i18n(NameConst.TT_SHIFT_FOR_MORE)); } @@ -415,7 +522,7 @@ public void draw() { } } - public void setState(TileLevelMaintainer.State state) { + public void setState(State state) { this.state = state; } } @@ -423,11 +530,11 @@ public void setState(TileLevelMaintainer.State state) { private class Widget { public final int idx; - public final String action; + public final Action action; private final FCGuiTextField textField; private final String tooltip; - public Widget(FCGuiTextField textField, String tooltip, int idx, String action) { + public Widget(FCGuiTextField textField, String tooltip, int idx, Action action) { this.textField = textField; this.textField.setEnableBackgroundDrawing(false); this.textField.setText("0"); diff --git a/src/main/java/com/glodblock/github/client/gui/GuiLevelTerminal.java b/src/main/java/com/glodblock/github/client/gui/GuiLevelTerminal.java new file mode 100644 index 000000000..6f34df8c5 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiLevelTerminal.java @@ -0,0 +1,1408 @@ +package com.glodblock.github.client.gui; + +import static com.glodblock.github.common.item.ItemWirelessUltraTerminal.hasInfinityBoosterCard; +import static com.glodblock.github.network.SPacketLevelTerminalUpdate.CLEAR_ALL_BIT; +import static com.glodblock.github.network.SPacketLevelTerminalUpdate.DISCONNECT_BIT; +import static com.glodblock.github.network.SPacketLevelTerminalUpdate.PacketAdd; +import static com.glodblock.github.network.SPacketLevelTerminalUpdate.PacketEntry; +import static com.glodblock.github.network.SPacketLevelTerminalUpdate.PacketOverwrite; +import static com.glodblock.github.network.SPacketLevelTerminalUpdate.PacketRemove; +import static com.glodblock.github.network.SPacketLevelTerminalUpdate.PacketRename; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.base.FCBaseMEGui; +import com.glodblock.github.client.gui.container.ContainerLevelTerminal; +import com.glodblock.github.common.tile.TileLevelMaintainer.State; +import com.glodblock.github.common.tile.TileLevelMaintainer.TLMTags; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.network.CPacketInventoryAction; +import com.glodblock.github.network.CPacketLevelTerminalCommands; +import com.glodblock.github.network.CPacketLevelTerminalCommands.Action; +import com.glodblock.github.network.CPacketRenamer; +import com.glodblock.github.util.FCGuiColors; +import com.glodblock.github.util.ModAndClassUtil; +import com.glodblock.github.util.NameConst; +import com.glodblock.github.util.Util; + +import appeng.api.config.Settings; +import appeng.api.config.TerminalStyle; +import appeng.api.config.YesNo; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.WorldCoord; +import appeng.client.gui.IGuiTooltipHandler; +import appeng.client.gui.widgets.GuiImgButton; +import appeng.client.gui.widgets.GuiScrollbar; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.client.gui.widgets.IDropToFillTextField; +import appeng.client.gui.widgets.MEGuiTextField; +import appeng.client.render.BlockPosHighlighter; +import appeng.container.AEBaseContainer; +import appeng.container.slot.AppEngSlot; +import appeng.core.AEConfig; +import appeng.core.localization.ButtonToolTips; +import appeng.core.localization.GuiColors; +import appeng.core.localization.GuiText; +import appeng.core.localization.PlayerMessages; +import appeng.helpers.InventoryAction; +import appeng.integration.IntegrationRegistry; +import appeng.integration.IntegrationType; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.Platform; +import appeng.util.ReadableNumberConverter; +import appeng.util.item.AEItemStack; +import cpw.mods.fml.common.Loader; + +public class GuiLevelTerminal extends FCBaseMEGui implements IDropToFillTextField, IGuiTooltipHandler { + + public static final int HEADER_HEIGHT = 52; + public static final int INV_HEIGHT = 98; + public static final int VIEW_WIDTH = 174; + public static final int VIEW_LEFT = 8; + private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/level_terminal.png"); + protected int offsetY; + private static final int offsetX = 21; + protected static String searchFieldOutputsText = ""; + protected static String searchFieldNamesText = ""; + protected static String currentMode = "OFF"; + private final MEGuiTextField searchFieldOutputs; + private final MEGuiTextField searchFieldNames; + private GuiImgButton searchStringSave; + private GuiImgButton terminalStyleBox; + + private ItemStack tooltipStack; + private boolean online; + private final boolean neiPresent; + private int viewHeight; + + protected GuiTabButton craftingStatusBtn; + // TODO: @Laiff: Implement command `enable_all`, `disable_all` main consern: + // TODO: Scheduling of all activated maintainers should be spreaded across ticks to not request all items on one + // tick + // private GuiFCImgButton modeSwitchView; + // private GuiFCImgButton modeSwitchEdit; + private final LevelTerminalList masterList = new LevelTerminalList(); + private final List extraOptionsText = new ArrayList<>(2); + private static final float ITEM_STACK_Z = 100.0f; + private static final float SLOT_Z = 0.5f; + private static final float ITEM_STACK_OVERLAY_Z = 200.0f; + private static final float SLOT_HOVER_Z = 310.0f; + private static final float TOOLTIP_Z = 410.0f; + private static final float STEP_Z = 10.0f; + private static final float MAGIC_RENDER_ITEM_Z = 50.0f; + + public GuiLevelTerminal(InventoryPlayer inventoryPlayer, Container container) { + super(inventoryPlayer, container); + setScrollBar(new GuiScrollbar()); + xSize = 208; + ySize = 255; + neiPresent = Loader.isModLoaded("NotEnoughItems"); + + searchFieldOutputs = new MEGuiTextField(86, 12, ButtonToolTips.SearchFieldOutputs.getLocal()) { + + @Override + public void onTextChange(final String oldText) { + masterList.markDirty(); + } + }; + + searchFieldNames = new MEGuiTextField(71, 12, ButtonToolTips.SearchFieldNames.getLocal()) { + + @Override + public void onTextChange(final String oldText) { + masterList.markDirty(); + } + }; + searchFieldNames.setFocused(true); + extraOptionsText.add(ButtonToolTips.HighlightInterface.getLocal()); + } + + public GuiLevelTerminal(final InventoryPlayer inventoryPlayer, final ITerminalHost te) { + this(inventoryPlayer, new ContainerLevelTerminal(inventoryPlayer, te)); + } + + @Override + public int getOffsetY() { + return offsetY; + } + + @Override + public void setOffsetY(int y) { + offsetY = y; + } + + private void setScrollBar() { + int maxScroll = masterList.getHeight() - viewHeight - 1; + if (maxScroll <= 0) { + getScrollBar().setTop(52).setLeft(189).setHeight(viewHeight).setRange(0, 0, 1); + } else { + getScrollBar().setTop(52).setLeft(189).setHeight(viewHeight).setRange(0, maxScroll, 12); + } + } + + @SuppressWarnings("unchecked") + @Override + public void initGui() { + super.initGui(); + viewHeight = calculateViewHeight(); + ySize = HEADER_HEIGHT + INV_HEIGHT + viewHeight; + final int unusedSpace = height - ySize; + guiTop = (int) Math.floor(unusedSpace / (unusedSpace < 0 ? 3.8f : 2.0f)); + + // modeSwitchView = new GuiFCImgButton(guiLeft + xSize - 40, guiTop + 1, "SWITCH", "OFF", false); + // modeSwitchEdit = new GuiFCImgButton(guiLeft + xSize - 40, guiTop + 1, "SWITCH", "ON", false); + offsetY = guiTop + 8; + terminalStyleBox = new GuiImgButton( + guiLeft - 18, + offsetY, + Settings.TERMINAL_STYLE, + AEConfig.instance.settings.getSetting(Settings.TERMINAL_STYLE)); + offsetY += 20; + searchStringSave = new GuiImgButton( + guiLeft - 18, + offsetY, + Settings.SAVE_SEARCH, + AEConfig.instance.settings.getSetting(Settings.SAVE_SEARCH)); + offsetY += 20; + + searchFieldOutputs.x = guiLeft + Math.max(32, offsetX); + searchFieldOutputs.y = guiTop + 38; + + searchFieldNames.x = guiLeft + Math.max(32, offsetX) + 99; + searchFieldNames.y = guiTop + 38; + + terminalStyleBox.xPosition = guiLeft - 18; + terminalStyleBox.yPosition = guiTop + 8; + craftingStatusBtn = new GuiTabButton( + guiLeft + xSize - 24, + guiTop - 4, + 2 + 11 * 16, + GuiText.CraftingStatus.getLocal(), + itemRender); + craftingStatusBtn.setHideEdge(13); + + if (ModAndClassUtil.isSearchBar && (AEConfig.instance.preserveSearchBar || isSubGui())) { + setSearchString(); + } + buttonList.add(terminalStyleBox); + buttonList.add(searchStringSave); + buttonList.add(craftingStatusBtn); + + setScrollBar(); + repositionSlots(); + initGuiDone(); + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + searchFieldOutputsText = searchFieldOutputs.getText(); + searchFieldNamesText = searchFieldNames.getText(); + } + + public void setSearchString() { + searchFieldOutputs.setText(searchFieldOutputsText); + searchFieldNames.setText(searchFieldNamesText); + } + + protected void repositionSlots() { + for (final Object obj : inventorySlots.inventorySlots) { + if (obj instanceof final AppEngSlot slot) { + slot.yDisplayPosition = slot.getY() + ySize - 78 - 4; + } + } + } + + private int getMaxViewHeight() { + return AEConfig.instance.getConfigManager().getSetting(Settings.TERMINAL_STYLE) == TerminalStyle.SMALL + ? AEConfig.instance.InterfaceTerminalSmallSize * 18 + : Integer.MAX_VALUE; + } + + protected int calculateViewHeight() { + final int maxViewHeight = getMaxViewHeight(); + final boolean hasNEI = IntegrationRegistry.INSTANCE.isEnabled(IntegrationType.NEI); + final int NEIPadding = hasNEI ? 22 /* input */ + 18 /* top panel */ : 0; + final int availableSpace = height - HEADER_HEIGHT - INV_HEIGHT - NEIPadding; + + // screen should use 95% of the space it can, 5% margins + return Math.min((int) (availableSpace * 0.95), maxViewHeight); + } + + @Override + public void drawFG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { + fontRendererObj.drawString( + StatCollector.translateToLocal(NameConst.GUI_LEVEL_TERMINAL), + 8, + 6, + GuiColors.InterfaceTerminalTitle.getColor()); + fontRendererObj.drawString( + GuiText.inventory.getLocal(), + GuiLevelTerminal.offsetX + 2, + ySize - 96 + 3, + GuiColors.InterfaceTerminalInventory.getColor()); + + if (!neiPresent && tooltipStack != null) { + renderToolTip(tooltipStack, mouseX, mouseY); + } + } + + @SuppressWarnings("unchecked") + @Override + public void drawScreen(final int mouseX, final int mouseY, final float btn) { + terminalStyleBox.set(AEConfig.instance.settings.getSetting(Settings.TERMINAL_STYLE)); + + buttonList.clear(); + buttonList.add(terminalStyleBox); + buttonList.add(searchStringSave); + buttonList.add(craftingStatusBtn); + // buttonList.add(Objects.equals(currentMode, "OFF") ? modeSwitchView : modeSwitchEdit); + addSwitchGuiBtns(); + + super.drawScreen(mouseX, mouseY, btn); + + handleTooltip(mouseX, mouseY, searchFieldOutputs); + handleTooltip(mouseX, mouseY, searchFieldNames); + } + + @Override + protected void mouseClicked(final int xCoord, final int yCoord, final int btn) { + boolean focusOut = searchFieldOutputs.isFocused(); + boolean focusName = searchFieldNames.isFocused(); + + searchFieldOutputs.mouseClicked(xCoord, yCoord, btn); + searchFieldNames.mouseClicked(xCoord, yCoord, btn); + + if (focusOut && !searchFieldOutputs.isFocused()) { + searchFieldOutputsText = searchFieldOutputs.getText(); + } else if (focusName && !searchFieldNames.isFocused()) { + searchFieldNamesText = searchFieldNames.getText(); + } + + if (masterList.mouseClicked(xCoord - guiLeft - VIEW_LEFT, yCoord - guiTop - HEADER_HEIGHT, btn)) { + return; + } + + super.mouseClicked(xCoord, yCoord, btn); + } + + @Override + protected void actionPerformed(final GuiButton btn) { +// if (btn == modeSwitchView) { +// currentMode = "ON"; +// } else if (btn == modeSwitchEdit) { +// currentMode = "OFF"; +// } else + if (ModAndClassUtil.isSaveText && btn == searchStringSave) { + + final boolean backwards = Mouse.isButtonDown(1); + final GuiImgButton iBtn = (GuiImgButton) btn; + final Enum cv = iBtn.getCurrentValue(); + final Enum next = Platform.rotateEnum(cv, backwards, iBtn.getSetting().getPossibleValues()); + AEConfig.instance.preserveSearchBar = next == YesNo.YES; + AEConfig.instance.settings.putSetting(Settings.SAVE_SEARCH, next); + searchStringSave.set(next); + + } else if (btn == craftingStatusBtn) { + InventoryHandler.switchGui(GuiType.CRAFTING_STATUS); + } else if (btn instanceof final GuiImgButton iBtn) { + if (iBtn.getSetting() != Settings.ACTIONS) { + final Enum cv = iBtn.getCurrentValue(); + final boolean backwards = Mouse.isButtonDown(1); + final Enum next = Platform.rotateEnum(cv, backwards, iBtn.getSetting().getPossibleValues()); + + if (btn == terminalStyleBox) { + AEConfig.instance.settings.putSetting(iBtn.getSetting(), next); + + reinitialize(); + } + + iBtn.set(next); + } + } + super.actionPerformed(btn); + } + + private void reinitialize() { + buttonList.clear(); + initGui(); + } + + @Override + public void drawBG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { + mc.getTextureManager().bindTexture(TEX_BG); + /* Draws the top part. */ + drawTexturedModalRect(offsetX, offsetY, 0, 0, xSize, HEADER_HEIGHT); + /* Draws the middle part. */ + Tessellator.instance.startDrawingQuads(); + addTexturedRectToTesselator( + offsetX, + offsetY + HEADER_HEIGHT, + offsetX + xSize, + offsetY + HEADER_HEIGHT + viewHeight + 1, + 0.0f, + 0.0f, + (HEADER_HEIGHT + LevelTerminalSection.TITLE_HEIGHT + 1.0f) / 256.0f, + xSize / 256.0f, + (HEADER_HEIGHT + 106.0f) / 256.0f); + Tessellator.instance.draw(); + /* Draw the bottom part */ + drawTexturedModalRect(offsetX, offsetY + HEADER_HEIGHT + viewHeight, 0, 158, xSize, INV_HEIGHT); + if (online) { + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + /* (0,0) => viewPort's (0,0) */ + GL11.glPushMatrix(); + GL11.glTranslatef(offsetX + VIEW_LEFT, offsetY + HEADER_HEIGHT, 0); + tooltipStack = null; + masterList.hoveredEntry = null; + drawViewport(mouseX - offsetX - VIEW_LEFT, mouseY - offsetY - HEADER_HEIGHT - 1); + GL11.glPopMatrix(); + GL11.glPopAttrib(); + } + searchFieldOutputs.drawTextBox(); + searchFieldNames.drawTextBox(); + } + + private void drawViewport(int relMouseX, int relMouseY) { + /* Viewport Magic */ + final int scroll = getScrollBar().getCurrentScroll(); + int viewY = -scroll; // current y in viewport coordinates + int entryIdx = 0; + List visibleSections = masterList.getVisibleSections(); + + final float guiScaleX = (float) mc.displayWidth / width; + final float guiScaleY = (float) mc.displayHeight / height; + GL11.glScissor( + (int) ((guiLeft + VIEW_LEFT) * guiScaleX), + (int) ((height - (guiTop + HEADER_HEIGHT + viewHeight)) * guiScaleY), + (int) (VIEW_WIDTH * guiScaleX), + (int) (viewHeight * guiScaleY)); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + + /* + * Render each section + */ + while (viewY < viewHeight && entryIdx < visibleSections.size()) { + LevelTerminalSection section = visibleSections.get(entryIdx); + int sectionHeight = section.getHeight(); + + /* Is it viewable/in the viewport at all? */ + if (viewY + sectionHeight < 0) { + entryIdx++; + viewY += sectionHeight; + section.visible = false; + continue; + } + + section.visible = true; + int advanceY = drawSection(section, viewY, relMouseX, relMouseY); + viewY += advanceY; + entryIdx++; + } + } + + private int drawSection(LevelTerminalSection section, int viewY, int relMouseX, int relMouseY) { + int title; + int renderY = 0; + final int sectionBottom = viewY + section.getHeight() - 1; + final int fontColor = GuiColors.InterfaceTerminalInventory.getColor(); + /* + * Render title + */ + mc.getTextureManager().bindTexture(TEX_BG); + if (sectionBottom > 0 && sectionBottom < LevelTerminalSection.TITLE_HEIGHT) { + title = sectionBottom; + } else if (viewY < 0) { + title = 0; + } else { + title = 0; + } + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + Iterator visible = section.getVisible(); + while (visible.hasNext()) { + if (viewY < viewHeight) { + renderY += drawEntry( + visible.next(), + viewY + LevelTerminalSection.TITLE_HEIGHT + renderY, + title, + relMouseX, + relMouseY); + } else { + LevelTerminalEntry entry = visible.next(); + entry.dispY = -9999; + entry.highlightButton.yPosition = -1; + entry.renameButton.yPosition = -1; + entry.configButton.yPosition = -1; + } + } + /* + * Render title + */ + mc.getTextureManager().bindTexture(TEX_BG); + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z + ITEM_STACK_Z + STEP_Z); + if (sectionBottom > 0 && sectionBottom < LevelTerminalSection.TITLE_HEIGHT) { + /* Transition draw */ + drawTexturedModalRect( + 0, + 0, + VIEW_LEFT, + HEADER_HEIGHT + LevelTerminalSection.TITLE_HEIGHT - sectionBottom, + VIEW_WIDTH, + sectionBottom); + fontRendererObj + .drawString(section.name, 2, sectionBottom - LevelTerminalSection.TITLE_HEIGHT + 2, fontColor); + } else if (viewY < 0) { + /* Hidden title draw */ + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glTranslatef(0.0f, 0.0f, 100f); + drawTexturedModalRect(0, 0, VIEW_LEFT, HEADER_HEIGHT, VIEW_WIDTH, LevelTerminalSection.TITLE_HEIGHT); + fontRendererObj.drawString(section.name, 2, 2, fontColor); + GL11.glEnable(GL11.GL_DEPTH_TEST); + } else { + /* Normal title draw */ + drawTexturedModalRect(0, viewY, VIEW_LEFT, HEADER_HEIGHT, VIEW_WIDTH, LevelTerminalSection.TITLE_HEIGHT); + fontRendererObj.drawString(section.name, 2, viewY + 2, fontColor); + } + GL11.glTranslatef(0.0f, 0.0f, -(ITEM_STACK_OVERLAY_Z + ITEM_STACK_Z + STEP_Z)); + + return LevelTerminalSection.TITLE_HEIGHT + renderY; + } + + private int drawEntry(LevelTerminalEntry entry, int viewY, int titleBottom, int relMouseX, int relMouseY) { + final EntityPlayer player = Minecraft.getMinecraft().thePlayer; + mc.getTextureManager().bindTexture(TEX_BG); + Tessellator.instance.startDrawingQuads(); + int relY = 0; + final int slotLeftMargin = (VIEW_WIDTH - entry.rowSize * 18); + float lastZLevel = aeRenderItem.zLevel; + + entry.dispY = viewY; + /* PASS 1: BG */ + for (int row = 0; row < entry.rows; ++row) { + final int rowYTop = row * 18; + final int rowYBot = rowYTop + 18; + + relY += 18; + /* Is the slot row in view? */ + if (viewY + rowYBot <= titleBottom) { + continue; + } + for (int col = 0; col < entry.rowSize; ++col) { + addTexturedRectToTesselator( + col * 18 + slotLeftMargin, + viewY + rowYTop, + 18 * col + 18 + slotLeftMargin, + viewY + rowYBot, + 0, + 21 / 256f, + 173 / 256f, + (21 + 18) / 256f, + (173 + 18) / 256f); + } + } + Tessellator.instance.draw(); + /* Draw button */ + if (viewY + entry.highlightButton.height > 0 && viewY < viewHeight) { + entry.highlightButton.yPosition = viewY + 1; + entry.renameButton.yPosition = viewY + 1; + entry.configButton.yPosition = viewY + 1; + GuiFCImgButton toRender; + if (isCtrlKeyDown() && isShiftKeyDown() && hasInfinityBoosterCard(player)) { + toRender = entry.configButton; + } else if (isShiftKeyDown()) { + toRender = entry.renameButton; + } else { + toRender = entry.highlightButton; + } + toRender.drawButton(mc, relMouseX, relMouseY); + if (toRender.getMouseIn() + && relMouseY >= Math.max(LevelTerminalSection.TITLE_HEIGHT, entry.highlightButton.yPosition)) { + // draw a tooltip + GL11.glTranslatef(0f, 0f, TOOLTIP_Z); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + drawHoveringText(Arrays.asList(toRender.getMessage()), relMouseX, relMouseY); + GL11.glTranslatef(0f, 0f, -TOOLTIP_Z); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + } + } else { + entry.highlightButton.yPosition = -1; + entry.renameButton.yPosition = -1; + } + /* PASS 2: Items */ + for (int row = 0; row < entry.rows; ++row) { + final int rowYTop = row * 18; + final int rowYBot = rowYTop + 18; + /* Is the slot row in view? */ + if (viewY + rowYBot <= titleBottom) { + continue; + } + AppEngInternalInventory inv = entry.getInventory(); + + for (int col = 0; col < entry.rowSize; ++col) { + final int colLeft = col * 18 + slotLeftMargin + 1; + final int colRight = colLeft + 18 + 1; + final int slotIdx = row * entry.rowSize + col; + ItemStack stack = inv.getStackInSlot(slotIdx); + + boolean tooltip = relMouseX > colLeft - 1 && relMouseX < colRight - 1 + && relMouseY >= Math.max(viewY + rowYTop, LevelTerminalSection.TITLE_HEIGHT) + && relMouseY < Math.min(viewY + rowYBot, viewHeight); + if (stack != null) { + + AEItemStack aeItemStack = AEItemStack.create(stack); + NBTTagCompound data = stack.getTagCompound(); + ItemStack itemStack = data.hasKey(TLMTags.Stack.tagName) + ? ItemStack.loadItemStackFromNBT(data.getCompoundTag(TLMTags.Stack.tagName)) + : stack.copy(); + long quantity = data.getLong(TLMTags.Quantity.tagName); + long batch = data.getLong(TLMTags.Batch.tagName); + State state = State.values()[data.getInteger(TLMTags.State.tagName)]; + NBTTagCompound linkTag = data.getCompoundTag(TLMTags.Link.tagName); + + GL11.glPushMatrix(); + GL11.glTranslatef(colLeft, viewY + rowYTop + 1, ITEM_STACK_Z); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + RenderHelper.enableGUIStandardItemLighting(); + itemStack.stackSize = 1; + aeItemStack.setStackSize(quantity); + aeRenderItem.setAeStack(aeItemStack); + aeRenderItem.zLevel = ITEM_STACK_Z - MAGIC_RENDER_ITEM_Z; + aeRenderItem.renderItemAndEffectIntoGUI(fontRendererObj, mc.getTextureManager(), itemStack, 0, 0); + aeRenderItem.renderItemOverlayIntoGUI(fontRendererObj, mc.getTextureManager(), itemStack, 0, 0); + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z - ITEM_STACK_Z); + int color = switch (state) { + case Idle -> FCGuiColors.StateIdle.getColor(); + case Craft -> FCGuiColors.StateCraft.getColor(); + case Export -> FCGuiColors.StateExport.getColor(); + case Error -> FCGuiColors.StateError.getColor(); + case None -> FCGuiColors.StateNone.getColor(); + }; + int offset = 0; + int size = 4; + drawRect(offset, offset, offset + size, offset + size, color); + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z - ITEM_STACK_Z); + this.drawReadableAmount(fontRendererObj, quantity, 16.0f, 12f, 16777215); + if (batch > 0) { + this.drawReadableAmount(fontRendererObj, batch, 16.0f, 1f, 16777215); + } + RenderHelper.disableStandardItemLighting(); + + /* + * Mouse overlay. such large z value because items are rendered at zLevel=100.0f, whatever that is + */ + if (!tooltip) { + if (entry.filteredRecipes[slotIdx]) { + GL11.glTranslatef(0.0f, 0.0f, ITEM_STACK_OVERLAY_Z); + drawRect(0, 0, 16, 16, GuiColors.ItemSlotOverlayUnpowered.getColor()); + } + } else { + tooltipStack = stack; + } + GL11.glPopMatrix(); + } else if (entry.filteredRecipes[slotIdx]) { + GL11.glPushMatrix(); + GL11.glTranslatef(colLeft, viewY + rowYTop + 1, ITEM_STACK_OVERLAY_Z); + drawRect(0, 0, 16, 16, GuiColors.ItemSlotOverlayUnpowered.getColor()); + GL11.glPopMatrix(); + } + if (tooltip) { + // overlay highlight + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glTranslatef(0.0f, 0.0f, SLOT_HOVER_Z); + drawRect(colLeft, viewY + 1 + rowYTop, -2 + colRight, viewY - 1 + rowYBot, 0x77FFFFFF); + GL11.glTranslatef(0.0f, 0.0f, -SLOT_HOVER_Z); + masterList.hoveredEntry = entry; + entry.hoveredSlotIdx = slotIdx; + } + GL11.glDisable(GL11.GL_LIGHTING); + } + } + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + aeRenderItem.zLevel = lastZLevel; + return relY + 1; + } + + public void drawReadableAmount(final FontRenderer fontRenderer, long amount, float x, float y, int color) { + + final float scaleFactor = AEConfig.instance.useTerminalUseLargeFont() ? 0.85f : 0.5f; + final float inverseScaleFactor = 1.0f / scaleFactor; + final int offset = AEConfig.instance.useTerminalUseLargeFont() ? 0 : -1; + final boolean unicodeFlag = fontRenderer.getUnicodeFlag(); + final String stackSize = this.getToBeRenderedStackSize(amount); + + fontRenderer.setUnicodeFlag(false); + + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glPushMatrix(); + GL11.glScaled(scaleFactor, scaleFactor, scaleFactor); + + final int X = (int) (((float) x + offset - fontRenderer.getStringWidth(stackSize) * scaleFactor) + * inverseScaleFactor); + final int Y = (int) (((float) y + offset * scaleFactor) * inverseScaleFactor); + + fontRenderer.drawString(stackSize, X + 1, Y, 0); + fontRenderer.drawString(stackSize, X - 1, Y, 0); + fontRenderer.drawString(stackSize, X, Y + 1, 0); + fontRenderer.drawString(stackSize, X, Y - 1, 0); + + fontRenderer.drawString(stackSize, X, Y, color); + + GL11.glPopMatrix(); + GL11.glEnable(GL11.GL_LIGHTING); + + fontRenderer.setUnicodeFlag(unicodeFlag); + } + + private String getToBeRenderedStackSize(final long originalSize) { + if (AEConfig.instance.useTerminalUseLargeFont()) { + return ReadableNumberConverter.INSTANCE.toSlimReadableForm(originalSize); + } else { + return ReadableNumberConverter.INSTANCE.toWideReadableForm(originalSize); + } + } + + @SuppressWarnings("unchecked") + @Override + public void drawHoveringText(List textLines, int x, int y, FontRenderer font) { + if (!textLines.isEmpty()) { + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + RenderHelper.disableStandardItemLighting(); + int maxStrWidth = 0; + + // is this more efficient than doing 1 pass, then doing a translate before drawing the text? + for (String s : (List) textLines) { + int width = font.getStringWidth(s); + + if (width > maxStrWidth) { + maxStrWidth = width; + } + } + + // top left corner + int curX = x + 12; + int curY = y - 12; + int totalHeight = 8; + + if (textLines.size() > 1) { + totalHeight += 2 + (textLines.size() - 1) * 10; + } + + /* String is too long? Display on the left side */ + if (curX + maxStrWidth > width) { + curX -= 28 + maxStrWidth; + } + + /* String is too tall? move it up */ + if (curY + totalHeight + 6 > height) { + curY = height - totalHeight - 6; + } + + int borderColor = -267386864; + // drawing the border... + drawGradientRect(curX - 3, curY - 4, curX + maxStrWidth + 3, curY - 3, borderColor, borderColor); + drawGradientRect( + curX - 3, + curY + totalHeight + 3, + curX + maxStrWidth + 3, + curY + totalHeight + 4, + borderColor, + borderColor); + drawGradientRect( + curX - 3, + curY - 3, + curX + maxStrWidth + 3, + curY + totalHeight + 3, + borderColor, + borderColor); + drawGradientRect(curX - 4, curY - 3, curX - 3, curY + totalHeight + 3, borderColor, borderColor); + drawGradientRect( + curX + maxStrWidth + 3, + curY - 3, + curX + maxStrWidth + 4, + curY + totalHeight + 3, + borderColor, + borderColor); + int color1 = 1347420415; + int color2 = (color1 & 16711422) >> 1 | color1 & -16777216; + drawGradientRect(curX - 3, curY - 3 + 1, curX - 3 + 1, curY + totalHeight + 3 - 1, color1, color2); + drawGradientRect( + curX + maxStrWidth + 2, + curY - 3 + 1, + curX + maxStrWidth + 3, + curY + totalHeight + 3 - 1, + color1, + color2); + drawGradientRect(curX - 3, curY - 3, curX + maxStrWidth + 3, curY - 3 + 1, color1, color1); + drawGradientRect( + curX - 3, + curY + totalHeight + 2, + curX + maxStrWidth + 3, + curY + totalHeight + 3, + color2, + color2); + + for (int i = 0; i < textLines.size(); ++i) { + String line = (String) textLines.get(i); + font.drawStringWithShadow(line, curX, curY, -1); + + if (i == 0) { + // gap between name and lore text + curY += 2; + } + + curY += 10; + } + + RenderHelper.enableGUIStandardItemLighting(); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } + } + + @Override + protected void keyTyped(final char character, final int key) { + if (!checkHotbarKeys(key)) { + if (character == ' ') { + if ((searchFieldOutputs.getText().isEmpty() && searchFieldOutputs.isFocused()) + || (searchFieldNames.getText().isEmpty() && searchFieldNames.isFocused())) + return; + } else if (character == '\t') { + if (handleTab()) return; + } + if (searchFieldOutputs.textboxKeyTyped(character, key) + || searchFieldNames.textboxKeyTyped(character, key)) { + masterList.markDirty(); + } else { + super.keyTyped(character, key); + } + } + } + + private boolean handleTab() { + if (searchFieldOutputs.isFocused()) { + searchFieldOutputs.setFocused(false); + searchFieldNames.setFocused(true); + return true; + } else if (searchFieldNames.isFocused()) { + searchFieldNames.setFocused(false); + searchFieldOutputs.setFocused(true); + return true; + } + return false; + } + + @Override + protected boolean mouseWheelEvent(int mouseX, int mouseY, int wheel) { + boolean isMouseInViewport = isMouseInViewport(mouseX, mouseY); + GuiScrollbar scrollbar = getScrollBar(); + if (isMouseInViewport && isCtrlKeyDown()) { + if (wheel < 0) { + scrollbar.setCurrentScroll(masterList.getHeight()); + } else { + getScrollBar().setCurrentScroll(0); + } + return true; + } else if (isMouseInViewport && isShiftKeyDown()) { + // advance to the next section + return masterList.scrollNextSection(wheel > 0); + } else { + return super.mouseWheelEvent(mouseX, mouseY, wheel); + } + } + + private boolean isMouseInViewport(int mouseX, int mouseY) { + return mouseX > guiLeft + VIEW_LEFT && mouseX < guiLeft + VIEW_LEFT + VIEW_WIDTH + && mouseY > guiTop + HEADER_HEIGHT + && mouseY < guiTop + HEADER_HEIGHT + viewHeight; + } + + public void postUpdate(List updates, int statusFlags) { + if ((statusFlags & CLEAR_ALL_BIT) == CLEAR_ALL_BIT) { + /* Should clear all client entries. */ + masterList.list.clear(); + } + /* Should indicate disconnected, so the terminal turns dark. */ + online = (statusFlags & DISCONNECT_BIT) != DISCONNECT_BIT; + + for (PacketEntry cmd : updates) { + parsePacketCmd(cmd); + } + masterList.markDirty(); + } + + private void parsePacketCmd(PacketEntry cmd) { + long id = cmd.entryId; + if (cmd instanceof PacketAdd addCmd) { + LevelTerminalEntry entry = new LevelTerminalEntry( + id, + addCmd.name, + addCmd.rows, + addCmd.rowSize, + addCmd.online).setLocation(addCmd.x, addCmd.y, addCmd.z, addCmd.dim, addCmd.side) + .setIcons(addCmd.selfItemStack, addCmd.displayItemStack).setItems(addCmd.items); + masterList.addEntry(entry); + } else if (cmd instanceof PacketRemove) { + masterList.removeEntry(id); + } else if (cmd instanceof PacketOverwrite owCmd) { + LevelTerminalEntry entry = masterList.list.get(id); + + if (entry == null) { + return; + } + + if (owCmd.onlineValid) { + entry.online = owCmd.online; + } + + if (owCmd.itemsValid) { + if (owCmd.allItemUpdate) { + entry.fullItemUpdate(owCmd.items, owCmd.validIndices.length); + } else { + entry.partialItemUpdate(owCmd.items, owCmd.validIndices); + } + } + masterList.isDirty = true; + } else if (cmd instanceof PacketRename renameCmd) { + LevelTerminalEntry entry = masterList.list.get(id); + + if (entry != null) { + if (StatCollector.canTranslate(renameCmd.newName)) { + entry.customName = StatCollector.translateToLocal(renameCmd.newName); + } else { + entry.customName = StatCollector.translateToFallback(renameCmd.newName); + } + } + masterList.isDirty = true; + } + } + + private boolean itemStackMatchesSearchTerm(final ItemStack itemStack, final String searchTerm) { + if (itemStack == null) { + return false; + } + + final String displayName = Platform.getItemDisplayName(itemStack).toLowerCase(); + + if (displayName.contains(searchTerm)) { + return true; + } + + return false; + } + + @Override + public boolean isOverTextField(final int mouseX, final int mouseY) { + return searchFieldOutputs.isMouseIn(mouseX, mouseY) || searchFieldNames.isMouseIn(mouseX, mouseY); + } + + @Override + public void setTextFieldValue(final String displayName, final int mousex, final int mousey, final ItemStack stack) { + if (searchFieldOutputs.isMouseIn(mousex, mousey)) { + searchFieldOutputs.setText(displayName); + } else if (searchFieldNames.isMouseIn(mousex, mousey)) { + searchFieldNames.setText(displayName); + } + } + + @Override + public List handleItemTooltip(ItemStack stack, int mouseX, int mouseY, List currentToolTip) { + return currentToolTip; + } + + @Override + public ItemStack getHoveredStack() { + return tooltipStack; + } + + /** + * Tracks the list of entries. + */ + private class LevelTerminalList { + + private final Map list = new HashMap<>(); + private final Map sections = new TreeMap<>(); + private final List visibleSections = new ArrayList<>(); + private boolean isDirty; + private int height; + private LevelTerminalEntry hoveredEntry; + + LevelTerminalList() { + isDirty = true; + } + + /** + * Performs a full update. + */ + private void update() { + height = 0; + visibleSections.clear(); + + for (LevelTerminalSection section : sections.values()) { + String query = GuiLevelTerminal.this.searchFieldNames.getText(); + if (!query.isEmpty() && !section.name.toLowerCase().contains(query.toLowerCase())) { + continue; + } + + section.isDirty = true; + if (section.getVisible().hasNext()) { + height += section.getHeight(); + visibleSections.add(section); + } + } + isDirty = false; + } + + public void markDirty() { + isDirty = true; + setScrollBar(); + } + + public int getHeight() { + if (isDirty) { + update(); + } + return height; + } + + /** + * Jump between sections. + */ + private boolean scrollNextSection(boolean up) { + GuiScrollbar scrollbar = getScrollBar(); + int viewY = scrollbar.getCurrentScroll(); + var sections = getVisibleSections(); + boolean result = false; + + if (up) { + int y = masterList.getHeight(); + int i = sections.size() - 1; + + while (y > 0 && i >= 0) { + y -= sections.get(i).getHeight(); + i -= 1; + if (y < viewY) { + result = true; + scrollbar.setCurrentScroll(y); + break; + } + } + } else { + int y = 0; + + for (LevelTerminalSection section : sections) { + if (y > viewY) { + result = true; + scrollbar.setCurrentScroll(y); + break; + } + y += section.getHeight(); + } + } + return result; + } + + public void addEntry(LevelTerminalEntry entry) { + LevelTerminalSection section = sections.get(entry.customName); + + if (section == null) { + section = new LevelTerminalSection(entry.customName); + sections.put(entry.customName, section); + } + section.addEntry(entry); + list.put(entry.id, entry); + isDirty = true; + } + + public void removeEntry(long id) { + LevelTerminalEntry entry = list.remove(id); + + if (entry != null) { + entry.section.removeEntry(entry); + } + } + + public List getVisibleSections() { + if (isDirty) { + update(); + } + return visibleSections; + } + + /** + * Mouse button click. + * + * @param relMouseX viewport coords mouse X + * @param relMouseY viewport coords mouse Y + * @param btn button code + */ + public boolean mouseClicked(int relMouseX, int relMouseY, int btn) { + if (relMouseX < 0 || relMouseX >= VIEW_WIDTH || relMouseY < 0 || relMouseY >= viewHeight) { + return false; + } + for (LevelTerminalSection section : getVisibleSections()) { + if (section.mouseClicked(relMouseX, relMouseY, btn)) { + return true; + } + } + return false; + } + } + + /** + * A section holds all the interface entries with the same name. + */ + private class LevelTerminalSection { + + public static final int TITLE_HEIGHT = 12; + + String name; + List entries = new ArrayList<>(); + Set visibleEntries = new TreeSet<>(Comparator.comparing(e -> { + if (e.displayItemStack != null) { + return e.displayItemStack.getDisplayName() + e.id; + } else { + return String.valueOf(e.id); + } + })); + int height; + private boolean isDirty = true; + boolean visible = false; + + LevelTerminalSection(String name) { + this.name = name; + } + + /** + * Gets the height. Includes title. + */ + public int getHeight() { + if (isDirty) { + update(); + } + return height; + } + + private void update() { + refreshVisible(); + if (visibleEntries.isEmpty()) { + height = 0; + } else { + height = TITLE_HEIGHT; + for (LevelTerminalEntry entry : visibleEntries) { + height += entry.guiHeight; + } + } + isDirty = false; + } + + public void refreshVisible() { + visibleEntries.clear(); + String output = GuiLevelTerminal.this.searchFieldOutputs.getText().toLowerCase(); + + for (LevelTerminalEntry entry : entries) { + entry.dispY = -9999; + // Find search terms + if (!output.isEmpty()) { + AppEngInternalInventory inv = entry.inv; + boolean shouldAdd = false; + + for (int i = 0; i < inv.getSizeInventory(); ++i) { + ItemStack stack = inv.getStackInSlot(i); + if (itemStackMatchesSearchTerm(stack, output)) { + shouldAdd = true; + entry.filteredRecipes[i] = false; + } else { + entry.filteredRecipes[i] = true; + } + } + if (!shouldAdd) { + continue; + } + } else { + Arrays.fill(entry.filteredRecipes, false); + } + visibleEntries.add(entry); + } + } + + public void addEntry(LevelTerminalEntry entry) { + entries.add(entry); + entry.section = this; + isDirty = true; + } + + public void removeEntry(LevelTerminalEntry entry) { + entries.remove(entry); + entry.section = null; + isDirty = true; + } + + public Iterator getVisible() { + if (isDirty) { + update(); + } + return visibleEntries.iterator(); + } + + public boolean mouseClicked(int relMouseX, int relMouseY, int btn) { + Iterator it = getVisible(); + boolean ret = false; + + while (it.hasNext() && !ret) { + ret = it.next().mouseClicked(relMouseX, relMouseY, btn); + } + + return ret; + } + } + + /** + * This class keeps track of an entry and its widgets. + */ + private class LevelTerminalEntry { + + String customName; + AppEngInternalInventory inv; + GuiFCImgButton highlightButton; + GuiFCImgButton renameButton; + GuiFCImgButton configButton; + /** Nullable - icon that represents the interface */ + ItemStack selfItemStack; + /** Nullable - icon that represents the interface's "target" */ + ItemStack displayItemStack; + LevelTerminalSection section; + long id; + int x, y, z, dim, side; + int rows, rowSize; + int guiHeight; + int dispY = -9999; + boolean online; + boolean[] filteredRecipes; + int numItems = 0; + private int hoveredSlotIdx = -1; + + LevelTerminalEntry(long id, String name, int rows, int rowSize, boolean online) { + this.id = id; + this.rows = rows; + this.rowSize = rowSize; + this.online = online; + if (StatCollector.canTranslate(name)) { + customName = StatCollector.translateToLocal(name); + } else { + String fallback = name + ".name"; // its whatever. save some bytes on network but looks ugly + if (StatCollector.canTranslate(fallback)) { + customName = StatCollector.translateToLocal(fallback); + } else { + customName = StatCollector.translateToFallback(name); + } + } + inv = new AppEngInternalInventory(null, rows * rowSize, 1); + highlightButton = new GuiFCImgButton(1, 0, "HIGHLIGHT", "YES"); + renameButton = new GuiFCImgButton(1, 0, "EDIT", "YES"); + configButton = new GuiFCImgButton(1, 0, "CONFIG", "YES"); + guiHeight = 18 * rows + 1; + filteredRecipes = new boolean[rows * rowSize]; + } + + LevelTerminalEntry setLocation(int x, int y, int z, int dim, int side) { + this.x = x; + this.y = y; + this.z = z; + this.dim = dim; + this.side = side; + + return this; + } + + LevelTerminalEntry setIcons(ItemStack selfItemStack, ItemStack displayItemStack) { + this.selfItemStack = selfItemStack; + this.displayItemStack = displayItemStack; + + return this; + } + + public void fullItemUpdate(NBTTagList items, int newSize) { + inv = new AppEngInternalInventory(null, newSize); + rows = newSize / rowSize; + numItems = 0; + + for (int i = 0; i < inv.getSizeInventory(); ++i) { + setItemInSlot(ItemStack.loadItemStackFromNBT(items.getCompoundTagAt(i)), i); + } + guiHeight = 18 * rows + 4; + } + + LevelTerminalEntry setItems(NBTTagList items) { + assert items.tagCount() == inv.getSizeInventory(); + + for (int i = 0; i < items.tagCount(); ++i) { + setItemInSlot(ItemStack.loadItemStackFromNBT(items.getCompoundTagAt(i)), i); + } + return this; + } + + public void partialItemUpdate(NBTTagList items, int[] validIndices) { + for (int i = 0; i < validIndices.length; ++i) { + setItemInSlot(ItemStack.loadItemStackFromNBT(items.getCompoundTagAt(i)), validIndices[i]); + } + } + + private void setItemInSlot(ItemStack stack, int idx) { + final int oldHasItem = inv.getStackInSlot(idx) != null ? 1 : 0; + final int newHasItem = stack != null ? 1 : 0; + + inv.setInventorySlotContents(idx, stack); + + // Update item count + numItems += newHasItem - oldHasItem; + assert numItems >= 0; + } + + public AppEngInternalInventory getInventory() { + return inv; + } + + public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) { + final EntityPlayer player = Minecraft.getMinecraft().thePlayer; + + if (!section.visible || mouseButton < 0 || mouseButton > 2) { + return false; + } + if (mouseX >= highlightButton.xPosition && mouseX < 2 + highlightButton.width + && mouseY > Math.max(highlightButton.yPosition, LevelTerminalSection.TITLE_HEIGHT) + && mouseY <= Math.min(highlightButton.yPosition + highlightButton.height, viewHeight)) { + highlightButton.func_146113_a(mc.getSoundHandler()); + Util.DimensionalCoordSide blockPos = new Util.DimensionalCoordSide( + x, + y, + z, + dim, + ForgeDirection.getOrientation(side), + ""); + if (isCtrlKeyDown() && isShiftKeyDown() && hasInfinityBoosterCard(player)) { + FluidCraft.proxy.netHandler.sendToServer( + new CPacketLevelTerminalCommands( + Action.EDIT, + blockPos.x, + blockPos.y, + blockPos.z, + blockPos.getDimension(), + blockPos.getSide())); + } else if (isShiftKeyDown()) { + FluidCraft.proxy.netHandler.sendToServer( + new CPacketRenamer( + blockPos.x, + blockPos.y, + blockPos.z, + blockPos.getDimension(), + blockPos.getSide())); + } else { + /* View in world */ + WorldCoord blockPos2 = new WorldCoord((int) player.posX, (int) player.posY, (int) player.posZ); + if (mc.theWorld.provider.dimensionId != dim) { + player.addChatMessage( + new ChatComponentTranslation(PlayerMessages.InterfaceInOtherDim.getName(), dim)); + } else { + BlockPosHighlighter.highlightBlock( + blockPos, + System.currentTimeMillis() + 500 * WorldCoord.getTaxicabDistance(blockPos, blockPos2)); + player.addChatMessage( + new ChatComponentTranslation( + PlayerMessages.InterfaceHighlighted.getName(), + blockPos.x, + blockPos.y, + blockPos.z)); + } + player.closeScreen(); + } + return true; + } + + int offsetY = mouseY - dispY; + int offsetX = mouseX - (VIEW_WIDTH - rowSize * 18) - 1; + if (offsetX >= 0 && offsetX < (rowSize * 18) + && mouseY > Math.max(dispY, LevelTerminalSection.TITLE_HEIGHT) + && offsetY < Math.min(viewHeight - dispY, guiHeight)) { + final int col = offsetX / 18; + final int row = offsetY / 18; + final int slotIdx = row * rowSize + col; + + // send packet to server, request an update + InventoryAction action = switch (mouseButton) { + case 0 -> { + // pickup / set-down. + yield null; + } + case 1 -> { + yield null; + } + case 2 -> { + // creative dupe: + if (player.capabilities.isCreativeMode) { + yield InventoryAction.CREATIVE_DUPLICATE; + } else { + yield InventoryAction.AUTO_CRAFT; + } + } + default -> { + // drop item: + yield null; + } + }; + + if (action != null) { + ItemStack itemStack = getInventory().getStackInSlot(slotIdx); + if (itemStack.hasTagCompound() && itemStack.getTagCompound().hasKey(TLMTags.Stack.tagName)) { + long batch = itemStack.getTagCompound().getLong(TLMTags.Batch.tagName); + NBTTagCompound stackData = itemStack.getTagCompound().getCompoundTag(TLMTags.Stack.tagName); + ItemStack is = ItemStack.loadItemStackFromNBT(stackData); + IAEItemStack stack = AEItemStack.create(is); + + if (stack == null) return true; + stack.setStackSize(batch); + ((AEBaseContainer) inventorySlots).setTargetStack(stack); + FluidCraft.proxy.netHandler.sendToServer(new CPacketInventoryAction(action, slotIdx, 0, stack)); + } + } + + return true; + } + + return false; + } + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiLevelWireless.java b/src/main/java/com/glodblock/github/client/gui/GuiLevelWireless.java new file mode 100644 index 000000000..45b716b3a --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/GuiLevelWireless.java @@ -0,0 +1,24 @@ +package com.glodblock.github.client.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import com.glodblock.github.client.gui.container.ContainerLevelWireless; +import com.glodblock.github.inventory.item.IWirelessTerminal; + +import appeng.container.slot.AppEngSlot; + +public class GuiLevelWireless extends GuiLevelTerminal { + + public GuiLevelWireless(final InventoryPlayer inventoryPlayer, final IWirelessTerminal te) { + super(inventoryPlayer, new ContainerLevelWireless(inventoryPlayer, te)); + } + + @Override + protected void repositionSlots() { + for (final Object obj : this.inventorySlots.inventorySlots) { + if (obj instanceof final AppEngSlot slot) { + slot.yDisplayPosition = this.ySize + slot.getY() - 78 - 4; + } + } + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/GuiPatternValueAmount.java b/src/main/java/com/glodblock/github/client/gui/GuiPatternValueAmount.java index 3f9debc5d..e14c9025e 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiPatternValueAmount.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiPatternValueAmount.java @@ -2,7 +2,6 @@ import net.minecraft.client.gui.GuiButton; import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.item.ItemStack; import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.base.FCGuiAmount; @@ -67,16 +66,16 @@ protected void actionPerformed(final GuiButton btn) { @Override protected void setOriginGUI(Object target) { if (target instanceof PartFluidPatternTerminal) { - this.myIcon = new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL, 1); + this.myIcon = ItemAndBlockHolder.FLUID_TERMINAL.stack(); this.originalGui = GuiType.FLUID_PATTERN_TERMINAL; } else if (target instanceof PartFluidPatternTerminalEx) { - this.myIcon = new ItemStack(ItemAndBlockHolder.FLUID_TERMINAL_EX, 1); + this.myIcon = ItemAndBlockHolder.FLUID_TERMINAL_EX.stack(); this.originalGui = GuiType.FLUID_PATTERN_TERMINAL_EX; - } else if (target instanceof IWirelessTerminal && ((IWirelessTerminal) target).isUniversal(target)) { - this.myIcon = new ItemStack(ItemAndBlockHolder.WIRELESS_ULTRA_TERM, 1); - this.originalGui = ItemWirelessUltraTerminal.readMode(((IWirelessTerminal) target).getItemStack()); + } else if (target instanceof IWirelessTerminal terminal && terminal.isUniversal(target)) { + this.myIcon = ItemAndBlockHolder.WIRELESS_ULTRA_TERM.stack(); + this.originalGui = ItemWirelessUltraTerminal.readMode(terminal.getItemStack()); } else if (target instanceof WirelessPatternTerminalInventory) { - this.myIcon = new ItemStack(ItemAndBlockHolder.WIRELESS_PATTERN_TERM, 1); + this.myIcon = ItemAndBlockHolder.WIRELESS_PATTERN_TERM.stack(); this.originalGui = GuiType.WIRELESS_FLUID_PATTERN_TERMINAL; } } diff --git a/src/main/java/com/glodblock/github/client/gui/GuiRenamer.java b/src/main/java/com/glodblock/github/client/gui/GuiRenamer.java index a81ec4cdf..116818155 100644 --- a/src/main/java/com/glodblock/github/client/gui/GuiRenamer.java +++ b/src/main/java/com/glodblock/github/client/gui/GuiRenamer.java @@ -1,5 +1,6 @@ package com.glodblock.github.client.gui; +import net.minecraft.client.gui.GuiButton; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; @@ -7,10 +8,19 @@ import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.ContainerRenamer; +import com.glodblock.github.common.item.ItemWirelessUltraTerminal; +import com.glodblock.github.common.parts.PartLevelTerminal; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.inventory.item.IWirelessTerminal; +import com.glodblock.github.inventory.item.WirelessInterfaceTerminalInventory; +import com.glodblock.github.inventory.item.WirelessLevelTerminalInventory; +import com.glodblock.github.loader.ItemAndBlockHolder; import com.glodblock.github.network.CPacketRenamer; import appeng.api.storage.ITerminalHost; import appeng.client.gui.AEBaseGui; +import appeng.client.gui.widgets.GuiTabButton; import appeng.client.gui.widgets.IDropToFillTextField; import appeng.client.gui.widgets.MEGuiTextField; import appeng.core.localization.GuiColors; @@ -18,20 +28,46 @@ public class GuiRenamer extends AEBaseGui implements IDropToFillTextField { - private final MEGuiTextField textField; + protected final MEGuiTextField textField; + + protected final ITerminalHost host; + protected GuiTabButton originalGuiBtn; + + protected ItemStack icon = null; public GuiRenamer(InventoryPlayer ip, ITerminalHost monitorable) { super(new ContainerRenamer(ip, monitorable)); + this.host = monitorable; this.xSize = 256; this.textField = new MEGuiTextField(230, 12); this.textField.setMaxStringLength(32); } + @SuppressWarnings("unchecked") @Override public void initGui() { super.initGui(); FluidCraft.proxy.netHandler.sendToServer(new CPacketRenamer(CPacketRenamer.Action.GET_TEXT)); + if (host instanceof PartLevelTerminal) { + icon = ItemAndBlockHolder.LEVEL_TERMINAL.stack(); + } else if (host instanceof IWirelessTerminal terminal && terminal.isUniversal(host)) { + icon = ItemAndBlockHolder.WIRELESS_ULTRA_TERM.stack(); + } else if (host instanceof WirelessLevelTerminalInventory) { + icon = ItemAndBlockHolder.WIRELESS_LEVEL_TERM.stack(); + } else if (host instanceof WirelessInterfaceTerminalInventory) { + icon = ItemAndBlockHolder.WIRELESS_INTERFACE_TERM.stack(); + } + if (this.icon != null) { + this.buttonList.add( + this.originalGuiBtn = new GuiTabButton( + this.guiLeft + 231, + this.guiTop - 4, + this.icon, + this.icon.getDisplayName(), + itemRender)); + this.originalGuiBtn.setHideEdge(13); + } this.textField.x = this.guiLeft + 12; this.textField.y = this.guiTop + 35; this.textField.setFocused(true); @@ -68,6 +104,25 @@ public boolean isOverTextField(final int mousex, final int mousey) { return textField.isMouseIn(mousex, mousey); } + @Override + protected void actionPerformed(GuiButton button) { + if (button == originalGuiBtn) { + switchGui(); + } else { + super.actionPerformed(button); + } + } + + public void switchGui() { + if (host instanceof PartLevelTerminal) InventoryHandler.switchGui(GuiType.LEVEL_TERMINAL); + else if (host instanceof IWirelessTerminal terminal && terminal.isUniversal(host)) + InventoryHandler.switchGui(ItemWirelessUltraTerminal.readMode(terminal.getItemStack())); + else if (host instanceof WirelessInterfaceTerminalInventory) + InventoryHandler.switchGui(GuiType.WIRELESS_INTERFACE_TERMINAL); + else if (host instanceof WirelessLevelTerminalInventory) + InventoryHandler.switchGui(GuiType.WIRELESS_LEVEL_TERMINAL); + } + public void setTextFieldValue(final String displayName, final int mousex, final int mousey, final ItemStack stack) { textField.setText(displayName); } diff --git a/src/main/java/com/glodblock/github/client/gui/base/FCBaseMEGui.java b/src/main/java/com/glodblock/github/client/gui/base/FCBaseMEGui.java index 7cf6ff2d4..90f29f01f 100644 --- a/src/main/java/com/glodblock/github/client/gui/base/FCBaseMEGui.java +++ b/src/main/java/com/glodblock/github/client/gui/base/FCBaseMEGui.java @@ -13,7 +13,8 @@ import com.glodblock.github.client.gui.GuiFluidPatternExWireless; import com.glodblock.github.client.gui.GuiFluidPatternWireless; import com.glodblock.github.client.gui.GuiFluidPortableCell; -import com.glodblock.github.client.gui.GuiInterfaceTerminalWireless; +import com.glodblock.github.client.gui.GuiInterfaceWireless; +import com.glodblock.github.client.gui.GuiLevelWireless; import com.glodblock.github.client.gui.container.base.FCBaseContainer; import com.glodblock.github.common.item.ItemWirelessUltraTerminal; import com.glodblock.github.inventory.gui.GuiType; @@ -29,7 +30,8 @@ public abstract class FCBaseMEGui extends AEBaseMEGui { protected GuiFCImgButton PatternTerminal; protected GuiFCImgButton EssentiaTerminal; protected GuiFCImgButton InterfaceTerminal; - protected GuiFCImgButton PatternTerminaleEx; + protected GuiFCImgButton LevelTerminal; + protected GuiFCImgButton PatternTerminalEx; protected List termBtns = new ArrayList<>(); protected boolean drawSwitchGuiBtn; @@ -87,13 +89,13 @@ protected void drawSwitchGuiBtns() { } if (!(this instanceof GuiFluidPatternExWireless)) { this.buttonList.add( - this.PatternTerminaleEx = new GuiFCImgButton( + this.PatternTerminalEx = new GuiFCImgButton( this.guiLeft - 18, this.getOffsetY(), "PATTERN_EX_TEM", "YES")); this.setOffsetY(this.getOffsetY() + 20); - termBtns.add(this.PatternTerminaleEx); + termBtns.add(this.PatternTerminalEx); } if (!(this instanceof GuiFluidPortableCell)) { this.buttonList.add( @@ -101,7 +103,7 @@ protected void drawSwitchGuiBtns() { this.setOffsetY(this.getOffsetY() + 20); termBtns.add(this.FluidTerminal); } - if (!(this instanceof GuiInterfaceTerminalWireless)) { + if (!(this instanceof GuiInterfaceWireless)) { this.buttonList.add( this.InterfaceTerminal = new GuiFCImgButton( this.guiLeft - 18, @@ -111,6 +113,12 @@ protected void drawSwitchGuiBtns() { this.setOffsetY(this.getOffsetY() + 20); termBtns.add(this.InterfaceTerminal); } + if (!(this instanceof GuiLevelWireless)) { + this.buttonList.add( + this.LevelTerminal = new GuiFCImgButton(this.guiLeft - 18, this.getOffsetY(), "LEVEL_TEM", "YES")); + this.setOffsetY(this.getOffsetY() + 20); + termBtns.add(this.LevelTerminal); + } if (ModAndClassUtil.ThE && !(this instanceof GuiEssentiaTerminal)) { this.buttonList.add( this.EssentiaTerminal = new GuiFCImgButton( @@ -123,6 +131,7 @@ protected void drawSwitchGuiBtns() { } } + @SuppressWarnings("unchecked") protected void addSwitchGuiBtns() { if (!drawSwitchGuiBtn) return; this.buttonList.addAll(termBtns); @@ -141,7 +150,9 @@ protected void actionPerformed(final GuiButton btn) { ItemWirelessUltraTerminal.switchTerminal(this.mc.thePlayer, GuiType.WIRELESS_FLUID_PATTERN_TERMINAL); } else if (btn == this.InterfaceTerminal) { ItemWirelessUltraTerminal.switchTerminal(this.mc.thePlayer, GuiType.WIRELESS_INTERFACE_TERMINAL); - } else if (btn == this.PatternTerminaleEx) { + } else if (btn == this.LevelTerminal) { + ItemWirelessUltraTerminal.switchTerminal(this.mc.thePlayer, GuiType.WIRELESS_LEVEL_TERMINAL); + } else if (btn == this.PatternTerminalEx) { ItemWirelessUltraTerminal.switchTerminal(this.mc.thePlayer, GuiType.WIRELESS_FLUID_PATTERN_TERMINAL_EX); } } diff --git a/src/main/java/com/glodblock/github/client/gui/base/FCGuiAmount.java b/src/main/java/com/glodblock/github/client/gui/base/FCGuiAmount.java index 86b58fa03..dff5eec0d 100644 --- a/src/main/java/com/glodblock/github/client/gui/base/FCGuiAmount.java +++ b/src/main/java/com/glodblock/github/client/gui/base/FCGuiAmount.java @@ -7,9 +7,8 @@ import org.lwjgl.input.Keyboard; -import com.glodblock.github.FluidCraft; +import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; -import com.glodblock.github.network.CPacketSwitchGuis; import appeng.client.gui.AEBaseGui; import appeng.client.gui.widgets.GuiTabButton; @@ -65,11 +64,12 @@ public void initGui() { if (this.originalGui != null && this.myIcon != null) { this.buttonList.add( this.originalGuiBtn = new GuiTabButton( - this.guiLeft + 154, - this.guiTop, + this.guiLeft + 151, + this.guiTop - 4, this.myIcon, this.myIcon.getDisplayName(), itemRender)); + this.originalGuiBtn.setHideEdge(13); } this.amountBox = new GuiTextField( @@ -106,7 +106,7 @@ protected void keyTyped(final char character, final int key) { protected void actionPerformed(final GuiButton btn) { super.actionPerformed(btn); if (btn == this.originalGuiBtn) { - FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(this.originalGui)); + InventoryHandler.switchGui(originalGui); } final boolean isPlus = btn == this.plus1 || btn == this.plus10 || btn == this.plus100 || btn == this.plus1000; final boolean isMinus = btn == this.minus1 || btn == this.minus10 diff --git a/src/main/java/com/glodblock/github/client/gui/base/FCGuiEncodeTerminal.java b/src/main/java/com/glodblock/github/client/gui/base/FCGuiEncodeTerminal.java index f2a9e9181..13cdac569 100644 --- a/src/main/java/com/glodblock/github/client/gui/base/FCGuiEncodeTerminal.java +++ b/src/main/java/com/glodblock/github/client/gui/base/FCGuiEncodeTerminal.java @@ -5,6 +5,7 @@ import net.minecraft.inventory.Slot; import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.GuiFCImgButton; @@ -15,7 +16,6 @@ import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.slot.SlotSingleItem; import com.glodblock.github.network.CPacketFluidPatternTermBtns; -import com.glodblock.github.util.Ae2ReflectClient; import com.glodblock.github.util.ModAndClassUtil; import appeng.api.storage.ITerminalHost; @@ -23,7 +23,6 @@ import appeng.client.gui.widgets.GuiImgButton; import appeng.client.gui.widgets.GuiScrollbar; import appeng.client.gui.widgets.GuiTabButton; -import appeng.client.render.AppEngRenderItem; import appeng.container.slot.AppEngSlot; import appeng.container.slot.SlotFake; import appeng.util.item.AEItemStack; @@ -54,7 +53,6 @@ public abstract class FCGuiEncodeTerminal extends GuiItemMonitor { protected GuiFCImgButton autoFillPatternEnableBtn; protected GuiFCImgButton autoFillPatternDisableBtn; protected final GuiScrollbar processingScrollBar = new GuiScrollbar(); - protected final AppEngRenderItem stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); public FCGuiEncodeTerminal(final InventoryPlayer inventoryPlayer, final ITerminalHost te, final FCContainerEncodeTerminal c) { @@ -184,13 +182,15 @@ public boolean drawSlot0(Slot slot) { if (ItemFluidPacket.getFluidStack(stack) != null && ItemFluidPacket.getFluidStack(stack).amount > 0) fake.setStackSize(ItemFluidPacket.getFluidStack(stack).amount); } else return true; - stackSizeRenderer.setAeStack(fake); - stackSizeRenderer.renderItemOverlayIntoGUI( + aeRenderItem.setAeStack(fake); + GL11.glTranslatef(0.0f, 0.0f, 200.0f); + aeRenderItem.renderItemOverlayIntoGUI( fontRendererObj, mc.getTextureManager(), stack.getItemStack(), slot.xDisplayPosition, slot.yDisplayPosition); + GL11.glTranslatef(0.0f, 0.0f, -200.0f); return false; } return true; diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidCraftConfirm.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidCraftConfirm.java index e49cfaa1a..878cd9f43 100644 --- a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidCraftConfirm.java +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidCraftConfirm.java @@ -9,6 +9,7 @@ import com.glodblock.github.common.item.ItemBaseWirelessTerminal; import com.glodblock.github.common.parts.PartFluidPatternTerminal; import com.glodblock.github.common.parts.PartFluidPatternTerminalEx; +import com.glodblock.github.common.parts.PartLevelTerminal; import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; import com.glodblock.github.inventory.item.IWirelessTerminal; @@ -35,6 +36,9 @@ public void switchToOriginalGUI() { if (ah instanceof PartFluidPatternTerminalEx) { originalGui = GuiType.FLUID_PATTERN_TERMINAL_EX; } + if (ah instanceof PartLevelTerminal) { + originalGui = GuiType.LEVEL_TERMINAL; + } if (ah instanceof IWirelessTerminal) { ItemStack terminal = ((IWirelessTerminal) ah).getItemStack(); if (terminal.getItem() instanceof ItemBaseWirelessTerminal) { diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerInterfaceWireless.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerInterfaceWireless.java index 1afa5f5c3..02bed9910 100644 --- a/src/main/java/com/glodblock/github/client/gui/container/ContainerInterfaceWireless.java +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerInterfaceWireless.java @@ -1,58 +1,23 @@ package com.glodblock.github.client.gui.container; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.inventory.IInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraftforge.common.util.ForgeDirection; import com.glodblock.github.client.gui.container.base.FCBaseContainer; import com.glodblock.github.inventory.item.IWirelessTerminal; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import appeng.api.networking.IGrid; -import appeng.api.networking.IGridNode; -import appeng.api.networking.security.IActionHost; -import appeng.api.util.DimensionalCoord; -import appeng.core.sync.network.NetworkHandler; -import appeng.core.sync.packets.PacketCompressedNBT; -import appeng.helpers.IInterfaceTerminalSupport; -import appeng.helpers.InterfaceTerminalSupportedClassProvider; +import appeng.container.implementations.ContainerInterfaceTerminal; import appeng.helpers.InventoryAction; -import appeng.items.misc.ItemEncodedPattern; -import appeng.parts.AEBasePart; -import appeng.tile.inventory.AppEngInternalInventory; -import appeng.util.InventoryAdaptor; import appeng.util.Platform; -import appeng.util.inv.AdaptorIInventory; -import appeng.util.inv.AdaptorPlayerHand; -import appeng.util.inv.ItemSlot; -import appeng.util.inv.WrapperInvSlot; public class ContainerInterfaceWireless extends FCBaseContainer { - /** - * this stuff is all server side - */ - private static long autoBase = Long.MIN_VALUE; - - private final Multimap supportedInterfaces = HashMultimap.create(); - private final Map byId = new HashMap<>(); - private IGrid grid; - private NBTTagCompound data = new NBTTagCompound(); + ContainerInterfaceTerminal delegateContainer; public ContainerInterfaceWireless(final InventoryPlayer ip, final IWirelessTerminal monitorable) { super(ip, monitorable); - if (Platform.isServer()) { - this.grid = monitorable.getActionableNode().getGrid(); - } + + delegateContainer = new ContainerInterfaceTerminal(ip, monitorable); this.bindPlayerInventory(ip, 14, 0); } @@ -64,330 +29,16 @@ public void detectAndSendChanges() { } super.detectAndSendChanges(); - if (this.grid == null) { - return; - } - - int total = 0; - boolean missing = false; - - final IActionHost host = this.getActionHost(); - if (host != null) { - final IGridNode agn = host.getActionableNode(); - if (agn != null && agn.isActive()) { - for (var clz : InterfaceTerminalSupportedClassProvider.getSupportedClasses()) { - for (final IGridNode gn : this.grid.getMachines(clz)) { - final IInterfaceTerminalSupport interfaceTerminalSupport = (IInterfaceTerminalSupport) gn - .getMachine(); - if (!gn.isActive() || !interfaceTerminalSupport.shouldDisplay()) continue; - - final Collection t = supportedInterfaces.get(interfaceTerminalSupport); - final String name = interfaceTerminalSupport.getName(); - missing = t.isEmpty() || t.stream().anyMatch(it -> !it.unlocalizedName.equals(name)); - total += interfaceTerminalSupport.getPatternsConfigurations().length; - if (missing) break; - } - // we can stop if any is missing. The value of `total` is not important if `missing == true` - if (missing) break; - } - } - } - - if (total != this.supportedInterfaces.size() || missing) { - this.regenList(this.data); - } else { - for (final ContainerInterfaceWireless.InvTracker inv : supportedInterfaces.values()) { - for (int x = 0; x < inv.client.getSizeInventory(); x++) { - if (this.isDifferent(inv.server.getStackInSlot(inv.offset + x), inv.client.getStackInSlot(x))) { - this.addItems(this.data, inv, x, 1); - } - } - } - } - - if (!this.data.hasNoTags()) { - try { - NetworkHandler.instance - .sendTo(new PacketCompressedNBT(this.data), (EntityPlayerMP) this.getPlayerInv().player); - } catch (final IOException ignored) {} - - this.data = new NBTTagCompound(); - } + delegateContainer.detectAndSendChanges(); } @Override public void doAction(final EntityPlayerMP player, final InventoryAction action, final int slot, final long id) { - final ContainerInterfaceWireless.InvTracker inv = this.byId.get(id); - if (inv != null) { - final ItemStack is = inv.server.getStackInSlot(slot + inv.offset); - final boolean hasItemInHand = player.inventory.getItemStack() != null; - - final InventoryAdaptor playerHand = new AdaptorPlayerHand(player); - - final WrapperInvSlot slotInv = new ContainerInterfaceWireless.PatternInvSlot(inv.server); - - final IInventory theSlot = slotInv.getWrapper(slot + inv.offset); - final InventoryAdaptor interfaceSlot = new AdaptorIInventory(theSlot); - - IInventory interfaceHandler = inv.server; - boolean canInsert = true; - - switch (action) { - case PICKUP_OR_SET_DOWN -> { - if (hasItemInHand) { - for (int s = 0; s < interfaceHandler.getSizeInventory(); s++) { - if (Platform.isSameItemPrecise( - interfaceHandler.getStackInSlot(s), - player.inventory.getItemStack())) { - canInsert = false; - break; - } - } - if (canInsert) { - ItemStack inSlot = theSlot.getStackInSlot(0); - if (inSlot == null) { - player.inventory.setItemStack(interfaceSlot.addItems(player.inventory.getItemStack())); - } else { - inSlot = inSlot.copy(); - final ItemStack inHand = player.inventory.getItemStack().copy(); - - theSlot.setInventorySlotContents(0, null); - player.inventory.setItemStack(null); - - player.inventory.setItemStack(interfaceSlot.addItems(inHand.copy())); - - if (player.inventory.getItemStack() == null) { - player.inventory.setItemStack(inSlot); - } else { - player.inventory.setItemStack(inHand); - theSlot.setInventorySlotContents(0, inSlot); - } - } - } - } else { - final IInventory mySlot = slotInv.getWrapper(slot + inv.offset); - mySlot.setInventorySlotContents(0, playerHand.addItems(mySlot.getStackInSlot(0))); - } - } - case SPLIT_OR_PLACE_SINGLE -> { - if (hasItemInHand) { - for (int s = 0; s < interfaceHandler.getSizeInventory(); s++) { - if (Platform.isSameItemPrecise( - interfaceHandler.getStackInSlot(s), - player.inventory.getItemStack())) { - canInsert = false; - break; - } - } - if (canInsert) { - ItemStack extra = playerHand.removeItems(1, null, null); - if (extra != null && !interfaceSlot.containsItems()) { - extra = interfaceSlot.addItems(extra); - } - if (extra != null) { - playerHand.addItems(extra); - } - } - } else if (is != null) { - ItemStack extra = interfaceSlot.removeItems((is.stackSize + 1) / 2, null, null); - if (extra != null) { - extra = playerHand.addItems(extra); - } - if (extra != null) { - interfaceSlot.addItems(extra); - } - } - } - case SHIFT_CLICK -> { - final IInventory mySlot = slotInv.getWrapper(slot + inv.offset); - final InventoryAdaptor playerInv = InventoryAdaptor.getAdaptor(player, ForgeDirection.UNKNOWN); - mySlot.setInventorySlotContents(0, mergeToPlayerInventory(playerInv, mySlot.getStackInSlot(0))); - } - case MOVE_REGION -> { - final InventoryAdaptor playerInvAd = InventoryAdaptor.getAdaptor(player, ForgeDirection.UNKNOWN); - for (int x = 0; x < inv.client.getSizeInventory(); x++) { - inv.server.setInventorySlotContents( - x + inv.offset, - mergeToPlayerInventory(playerInvAd, inv.server.getStackInSlot(x + inv.offset))); - } - } - case CREATIVE_DUPLICATE -> { - if (player.capabilities.isCreativeMode && !hasItemInHand) { - player.inventory.setItemStack(is == null ? null : is.copy()); - } - } - default -> { - return; - } - } - - this.updateHeld(player); - } - } - - private ItemStack mergeToPlayerInventory(InventoryAdaptor playerInv, ItemStack stack) { - if (stack == null) return null; - for (ItemSlot slot : playerInv) { - if (Platform.isSameItemPrecise(slot.getItemStack(), stack)) { - if (slot.getItemStack().stackSize < slot.getItemStack().getMaxStackSize()) { - ++slot.getItemStack().stackSize; - return null; - } - } - } - return playerInv.addItems(stack); - } - - private void regenList(final NBTTagCompound data) { - this.byId.clear(); - this.supportedInterfaces.clear(); - - final IActionHost host = this.getActionHost(); - if (host != null) { - final IGridNode agn = host.getActionableNode(); - if (agn != null && agn.isActive()) { - for (var clz : InterfaceTerminalSupportedClassProvider.getSupportedClasses()) { - for (final IGridNode gn : this.grid.getMachines(clz)) { - final IInterfaceTerminalSupport terminalSupport = (IInterfaceTerminalSupport) gn.getMachine(); - if (!gn.isActive() || !terminalSupport.shouldDisplay()) continue; - - final var configurations = terminalSupport.getPatternsConfigurations(); - - for (int i = 0; i < configurations.length; ++i) { - this.supportedInterfaces.put( - terminalSupport, - new ContainerInterfaceWireless.InvTracker(terminalSupport, configurations[i], i)); - } - } - } - } - } - - data.setBoolean("clear", true); - - for (final ContainerInterfaceWireless.InvTracker inv : this.supportedInterfaces.values()) { - this.byId.put(inv.which, inv); - this.addItems(data, inv, 0, inv.client.getSizeInventory()); - } + delegateContainer.doAction(player, action, slot, id); } @Override protected boolean isWirelessTerminal() { return true; } - - private boolean isDifferent(final ItemStack a, final ItemStack b) { - if (a == null && b == null) { - return false; - } - - if (a == null || b == null) { - return true; - } - - return !ItemStack.areItemStacksEqual(a, b); - } - - private void addItems(final NBTTagCompound data, final ContainerInterfaceWireless.InvTracker inv, final int offset, - final int length) { - final String name = '=' + Long.toString(inv.which, Character.MAX_RADIX); - final NBTTagCompound tag = data.getCompoundTag(name); - - if (tag.hasNoTags()) { - tag.setLong("sortBy", inv.sortBy); - tag.setString("un", inv.unlocalizedName); - tag.setInteger("x", inv.X); - tag.setInteger("y", inv.Y); - tag.setInteger("z", inv.Z); - tag.setInteger("dim", inv.dim); - tag.setInteger("side", inv.side.ordinal()); - tag.setInteger("size", inv.client.getSizeInventory()); - } - - for (int x = 0; x < length; x++) { - final NBTTagCompound itemNBT = new NBTTagCompound(); - - final ItemStack is = inv.server.getStackInSlot(x + offset + inv.offset); - - // "update" client side. - inv.client.setInventorySlotContents(offset + x, is == null ? null : is.copy()); - - if (is != null) { - is.writeToNBT(itemNBT); - } - - tag.setTag(Integer.toString(x + offset), itemNBT); - } - - data.setTag(name, tag); - } - - private static class InvTracker { - - private final long sortBy; - private final long which = autoBase++; - private final String unlocalizedName; - private final IInventory client; - private final IInventory server; - private final int offset; - private final int X; - private final int Y; - private final int Z; - private final int dim; - private final ForgeDirection side; - - public InvTracker(final DimensionalCoord coord, long sortValue, final IInventory patterns, - final String unlocalizedName, int offset, int size, ForgeDirection side) { - this( - coord.x, - coord.y, - coord.z, - coord.getDimension(), - sortValue, - patterns, - unlocalizedName, - offset, - size, - side); - } - - public InvTracker(int x, int y, int z, int dim, long sortValue, final IInventory patterns, - final String unlocalizedName, int offset, int size, ForgeDirection side) { - this.server = patterns; - this.client = new AppEngInternalInventory(null, size); - this.unlocalizedName = unlocalizedName; - this.sortBy = sortValue + offset << 16; - this.offset = offset; - this.X = x; - this.Y = y; - this.Z = z; - this.dim = dim; - this.side = side; - } - - public InvTracker(IInterfaceTerminalSupport terminalSupport, - IInterfaceTerminalSupport.PatternsConfiguration configuration, int index) { - this( - terminalSupport.getLocation(), - terminalSupport.getSortValue(), - terminalSupport.getPatterns(index), - terminalSupport.getName(), - configuration.offset, - configuration.size, - terminalSupport instanceof AEBasePart ? ((AEBasePart) terminalSupport).getSide() - : ForgeDirection.UNKNOWN); - } - } - - private static class PatternInvSlot extends WrapperInvSlot { - - public PatternInvSlot(final IInventory inv) { - super(inv); - } - - @Override - public boolean isItemValid(final ItemStack itemstack) { - return itemstack != null && itemstack.getItem() instanceof ItemEncodedPattern; - } - } } diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java index 8a31cb7fe..d8882f98d 100644 --- a/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelMaintainer.java @@ -1,16 +1,25 @@ package com.glodblock.github.client.gui.container; +import java.util.Objects; + import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import com.glodblock.github.common.tile.TileLevelMaintainer; +import com.glodblock.github.common.tile.TileLevelMaintainer.State; +import com.glodblock.github.common.tile.TileLevelMaintainer.TLMTags; import com.glodblock.github.inventory.AeItemStackHandler; import com.glodblock.github.inventory.slot.SlotFluidConvertingFake; +import com.glodblock.github.util.Util; +import appeng.api.config.SecurityPermissions; import appeng.container.AEBaseContainer; -import appeng.util.item.AEItemStack; +import appeng.helpers.InventoryAction; +import appeng.util.Platform; public class ContainerLevelMaintainer extends AEBaseContainer { @@ -37,15 +46,111 @@ public SlotFluidConvertingFake[] getRequestSlots() { return this.requestSlots; } + @Override + public void doAction(EntityPlayerMP player, InventoryAction action, int slotId, long id) { + Slot slot = getSlot(slotId); + if (slot instanceof SlotFluidConvertingFake) { + final ItemStack stack = player.inventory.getItemStack(); + switch (action) { + case PICKUP_OR_SET_DOWN -> { + if (stack == null) { + slot.putStack(null); + } else { + ((SlotFluidConvertingFake) slot).putConvertedStack(createLevelValues(stack.copy())); + } + } + case PLACE_SINGLE -> { + if (stack != null) { + ((SlotFluidConvertingFake) slot).putConvertedStack( + createLevelValues(Objects.requireNonNull(Util.copyStackWithSize(stack, 1)))); + } + } + case SPLIT_OR_PLACE_SINGLE -> { + ItemStack inSlot = slot.getStack(); + if (inSlot != null) { + if (stack == null) { + slot.putStack( + createLevelValues( + Objects.requireNonNull( + Util.copyStackWithSize( + inSlot, + Math.max(1, inSlot.stackSize - 1))))); + } else if (stack.isItemEqual(inSlot)) { + slot.putStack( + createLevelValues( + Objects.requireNonNull( + Util.copyStackWithSize( + inSlot, + Math.min( + inSlot.getMaxStackSize(), + inSlot.stackSize + 1))))); + } else { + ((SlotFluidConvertingFake) slot).putConvertedStack( + createLevelValues(Objects.requireNonNull(Util.copyStackWithSize(stack, 1)))); + } + } else if (stack != null) { + ((SlotFluidConvertingFake) slot).putConvertedStack( + createLevelValues(Objects.requireNonNull(Util.copyStackWithSize(stack, 1)))); + } + } + } + } else { + super.doAction(player, action, slotId, id); + } + } + @Override public ItemStack transferStackInSlot(EntityPlayer player, int idx) { - for (SlotFluidConvertingFake slot : this.getRequestSlots()) { + if (Platform.isClient()) { + return null; + } + + for (int i = 0; i < this.getRequestSlots().length; i++) { + SlotFluidConvertingFake slot = this.getRequestSlots()[i]; if (!slot.getHasStack()) { - slot.setAeStack(AEItemStack.create(((Slot) this.inventorySlots.get(idx)).getStack()), true); + ItemStack itemStack = ((Slot) this.inventorySlots.get(idx)).getStack(); + ItemStack configuration = createLevelValues(itemStack.copy()); + configuration.getTagCompound().setInteger(TLMTags.Index.tagName, i); + slot.putConvertedStack(configuration); break; } } + this.detectAndSendChanges(); return null; } + + @Override + public void detectAndSendChanges() { + this.verifyPermissions(SecurityPermissions.BUILD, false); + + super.detectAndSendChanges(); + } + + public static ItemStack createLevelValues(ItemStack itemStack) { + var data = itemStack.hasTagCompound() ? itemStack.getTagCompound() : new NBTTagCompound(); + if (!data.hasKey(TLMTags.Stack.tagName)) { + var itemStackTag = new NBTTagCompound(); + itemStack.copy().writeToNBT(itemStackTag); + data.setTag(TLMTags.Stack.tagName, itemStackTag); + } + if (!data.hasKey(TLMTags.Quantity.tagName)) { + data.setLong(TLMTags.Quantity.tagName, itemStack.stackSize > 0 ? itemStack.stackSize : 1); + } + if (!data.hasKey(TLMTags.Batch.tagName)) { + data.setLong(TLMTags.Batch.tagName, 1); + } + if (!data.hasKey(TLMTags.Enable.tagName)) { + data.setBoolean(TLMTags.Enable.tagName, false); + } + if (data.hasKey(TLMTags.Index.tagName)) { + data.removeTag(TLMTags.Index.tagName); + } + + data.setInteger(TLMTags.State.tagName, State.None.ordinal()); + itemStack.setTagCompound(data); + + return itemStack; + } + } diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelTerminal.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelTerminal.java new file mode 100644 index 000000000..7a69c6152 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelTerminal.java @@ -0,0 +1,406 @@ +package com.glodblock.github.client.gui.container; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.ForgeDirection; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.api.registries.ILevelViewable; +import com.glodblock.github.client.gui.container.base.FCBaseContainer; +import com.glodblock.github.common.parts.PartLevelTerminal; +import com.glodblock.github.coremod.registries.LevelTerminalRegistry; +import com.glodblock.github.inventory.item.IWirelessTerminal; +import com.glodblock.github.network.SPacketLevelTerminalUpdate; +import com.google.common.primitives.Ints; + +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.security.IActionHost; +import appeng.api.storage.ITerminalHost; +import appeng.api.util.DimensionalCoord; +import appeng.helpers.InventoryAction; +import appeng.items.misc.ItemEncodedPattern; +import appeng.util.InventoryAdaptor; +import appeng.util.Platform; +import appeng.util.inv.AdaptorPlayerHand; +import appeng.util.inv.ItemSlot; + +public class ContainerLevelTerminal extends FCBaseContainer { + + /** + * this stuff is all server side + */ + private int nextId = 0; + + private final Map tracked = new HashMap<>(); + private final Map trackedById = new HashMap<>(); + + private IGrid grid; + private SPacketLevelTerminalUpdate dirty; + private boolean isDirty; + private boolean wasOff; + private int ticks = 0; + + public ContainerLevelTerminal(final InventoryPlayer ip, final ITerminalHost monitorable) { + super(ip, monitorable); + if (Platform.isServer()) { + if (monitorable instanceof PartLevelTerminal terminal) { + grid = terminal.getActionableNode().getGrid(); + } else if (monitorable instanceof IWirelessTerminal wirelessTerminal) { + grid = wirelessTerminal.getActionableNode().getGrid(); + } + dirty = this.updateList(); + if (dirty != null) { + this.isDirty = true; + } else { + dirty = new SPacketLevelTerminalUpdate(); + } + } + + this.bindPlayerInventory(ip, 14, 0); + } + + @Override + public void detectAndSendChanges() { + if (Platform.isClient()) { + return; + } + + super.detectAndSendChanges(); + + if (this.grid == null) { + return; + } + + final IActionHost host = this.getActionHost(); + + if (!host.getActionableNode().isActive()) { + if (!wasOff) { + SPacketLevelTerminalUpdate update = new SPacketLevelTerminalUpdate(); + + update.setDisconnect(); + wasOff = true; + FluidCraft.proxy.netHandler.sendTo(update, (EntityPlayerMP) this.getPlayerInv().player); + } + return; + } + wasOff = false; + + if (isDirty) { + FluidCraft.proxy.netHandler.sendTo(dirty, (EntityPlayerMP) this.getPlayerInv().player); + dirty = new SPacketLevelTerminalUpdate(); + isDirty = false; + } else if (++ticks % 20 == 0) { + ticks = 0; + SPacketLevelTerminalUpdate update = this.updateList(); + if (update != null) { + FluidCraft.proxy.netHandler.sendTo(update, (EntityPlayerMP) this.getPlayerInv().player); + } + } + } + + /** + * Merge from slot -> player inv. Returns the items not added. + */ + private ItemStack mergeToPlayerInventory(InventoryAdaptor playerInv, ItemStack stack) { + if (stack == null) return null; + for (ItemSlot slot : playerInv) { + if (Platform.isSameItemPrecise(slot.getItemStack(), stack)) { + if (slot.getItemStack().stackSize < slot.getItemStack().getMaxStackSize()) { + ++slot.getItemStack().stackSize; + return null; + } + } + } + return playerInv.addItems(stack); + } + + @Override + public void doAction(final EntityPlayerMP player, final InventoryAction action, final int slotIdx, final long id) { + final ContainerLevelTerminal.InvTracker invTracker = this.trackedById.get(id); + if (invTracker != null) { + final ItemStack handStack = player.inventory.getItemStack(); + + if (handStack != null && !(handStack.getItem() instanceof ItemEncodedPattern)) { + // Why even bother if we're not dealing with an encoded pattern in hand + return; + } + + final ItemStack slotStack = invTracker.requests.getStackInSlot(slotIdx); + final InventoryAdaptor playerHand = new AdaptorPlayerHand(player); + + switch (action) { + /* Set down/pickup. This is the same as SPLIT_OR_PLACE_SINGLE as our max stack sizes are 1 in slots. */ + case PICKUP_OR_SET_DOWN -> { + if (handStack != null) { + for (int s = 0; s < invTracker.requests.getSizeInventory(); s++) { + /* Is there a duplicate pattern here? */ + if (Platform.isSameItemPrecise(invTracker.requests.getStackInSlot(s), handStack)) { + /* We're done here - dupe found. */ + return; + } + } + } + + if (slotStack == null) { + /* Insert to container, if valid */ + if (handStack == null) { + /* Nothing happens */ + return; + } + invTracker.requests.setInventorySlotContents(slotIdx, playerHand.removeItems(1, null, null)); + } else { + /* Exchange? */ + if (handStack != null && handStack.stackSize > 1) { + /* Exchange is impossible, abort */ + return; + } + invTracker.requests.setInventorySlotContents(slotIdx, playerHand.removeItems(1, null, null)); + playerHand.addItems(slotStack.copy()); + } + syncLevelTerminalSlot(invTracker, id, slotIdx, invTracker.requests.getStackInSlot(slotIdx)); + } + /* Shift click from slotIdx -> player. Player -> slotIdx is not supported. */ + case SHIFT_CLICK -> { + InventoryAdaptor playerInv = InventoryAdaptor.getAdaptor(player.inventory, ForgeDirection.UNKNOWN); + ItemStack leftOver = mergeToPlayerInventory(playerInv, slotStack); + + if (leftOver == null) { + invTracker.requests.setInventorySlotContents(slotIdx, null); + syncLevelTerminalSlot(invTracker, id, slotIdx, null); + } + } + /* Move all blank patterns -> player */ + case MOVE_REGION -> { + final InventoryAdaptor playerInv = InventoryAdaptor.getAdaptor(player, ForgeDirection.UNKNOWN); + List valid = new ArrayList<>(); + + for (int i = 0; i < invTracker.requests.getSizeInventory(); i++) { + ItemStack toExtract = invTracker.requests.getStackInSlot(i); + + if (toExtract == null) { + continue; + } + + ItemStack leftOver = mergeToPlayerInventory(playerInv, toExtract); + + if (leftOver != null) { + break; + } else { + invTracker.requests.setInventorySlotContents(i, null); + } + valid.add(i); + } + if (!valid.isEmpty()) { + int[] validIndices = Ints.toArray(valid); + NBTTagList tag = new NBTTagList(); + for (int i = 0; i < valid.size(); ++i) { + tag.appendTag(new NBTTagCompound()); + } + dirty.addOverwriteEntry(id).setItems(validIndices, tag); + isDirty = true; + } + } + case CREATIVE_DUPLICATE -> { + if (player.capabilities.isCreativeMode) { + playerHand.addItems(handStack); + } + } + default -> { + return; + } + } + + this.updateHeld(player); + } + } + + private void syncLevelTerminalSlot(ContainerLevelTerminal.InvTracker inv, long id, int slot, ItemStack stack) { + int[] validIndices = { slot }; + NBTTagList list = new NBTTagList(); + NBTTagCompound item = new NBTTagCompound(); + + if (stack != null) { + stack.writeToNBT(item); + } + list.appendTag(item); + inv.updateNBT(); + this.dirty.addOverwriteEntry(id).setItems(validIndices, list); + this.isDirty = true; + } + + private SPacketLevelTerminalUpdate updateList() { + SPacketLevelTerminalUpdate update = null; + var supported = LevelTerminalRegistry.instance().getSupportedClasses(); + Set visited = new HashSet<>(); + + for (Class clz : supported) { + boolean isAdopted = LevelTerminalRegistry.instance().isAdopted(clz); + Class machineClass = isAdopted ? LevelTerminalRegistry.instance().getAdopted(clz) + : clz; + for (IGridNode gridNode : grid.getMachines(machineClass)) { + final IGridHost gridHost = gridNode.getMachine(); + final ILevelViewable machine = isAdopted + ? LevelTerminalRegistry.instance().getAdapter(clz).adapt(gridHost) + : (ILevelViewable) gridHost; + + /* First check if we are already tracking this node */ + if (tracked.containsKey(gridHost)) { + /* Check for updates */ + ContainerLevelTerminal.InvTracker knownTracker = tracked.get(gridHost); + + /* Name changed? */ + String name = machine.getCustomName(); + + if (!Objects.equals(knownTracker.name, name)) { + if (update == null) update = new SPacketLevelTerminalUpdate(); + update.addRenamedEntry(knownTracker.id, name); + knownTracker.name = name; + } + + /* Status changed? */ + boolean isActive = gridNode.isActive() || machine.shouldDisplay(); + + if (!knownTracker.online && isActive) { + /* Node offline -> online */ + knownTracker.online = true; + if (update == null) update = new SPacketLevelTerminalUpdate(); + knownTracker.updateNBT(); + update.addOverwriteEntry(knownTracker.id).setOnline(true) + .setItems(knownTracker.requests.getSizeInventory(), knownTracker.inventoryNbt); + } else if (knownTracker.online && !isActive) { + /* Node online -> offline */ + knownTracker.online = false; + if (update == null) update = new SPacketLevelTerminalUpdate(); + update.addOverwriteEntry(knownTracker.id).setOnline(false); + } + + for (int i = 0; i < knownTracker.requests.getSizeInventory(); i++) { + ItemStack knowmItemStack = ItemStack + .loadItemStackFromNBT(knownTracker.inventoryNbt.getCompoundTagAt(i)); + ItemStack machineItemStack = machine.getInventoryByName("config").getStackInSlot(i); + if (isDifferent(knowmItemStack, machineItemStack)) { + if (update == null) update = new SPacketLevelTerminalUpdate(); + knownTracker.updateNBT(); + update.addOverwriteEntry(knownTracker.id) + .setItems(knownTracker.requests.getSizeInventory(), knownTracker.inventoryNbt); + } + } + } else { + /* Add a new entry */ + if (update == null) update = new SPacketLevelTerminalUpdate(); + ContainerLevelTerminal.InvTracker entry = new ContainerLevelTerminal.InvTracker( + nextId++, + machine, + gridNode.isActive()); + update.addNewEntry(entry.id, entry.name, entry.online) + .setLocation(entry.x, entry.y, entry.z, entry.dim, entry.side.ordinal()) + .setItems(entry.rows, entry.rowSize, entry.inventoryNbt) + .setViewItemStack(machine.getSelfItemStack(), machine.getDisplayItemStack()); + tracked.put(gridHost, entry); + trackedById.put(entry.id, entry); + } + visited.add(gridHost); + } + } + + /* Now find any entries that we need to remove */ + Iterator> it = tracked.entrySet().iterator(); + while (it.hasNext()) { + var entry = it.next(); + if (visited.contains(entry.getKey())) { + continue; + } + + if (update == null) update = new SPacketLevelTerminalUpdate(); + + trackedById.remove(entry.getValue().id); + it.remove(); + update.addRemovalEntry(entry.getValue().id); + } + return update; + } + + @Override + protected boolean isWirelessTerminal() { + return false; + } + + private boolean isDifferent(final ItemStack a, final ItemStack b) { + if (a == null && b == null) { + return false; + } + + if (a == null || b == null) { + return true; + } + + return !ItemStack.areItemStacksEqual(a, b); + } + + private static class InvTracker { + + private final long id; + private String name; + private final IInventory requests; + private final int rowSize; + private final int rows; + private final int x; + private final int y; + private final int z; + private final int dim; + private final ForgeDirection side; + private boolean online; + private NBTTagList inventoryNbt; + + public InvTracker(long id, ILevelViewable machine, boolean online) { + + DimensionalCoord location = machine.getLocation(); + + this.id = id; + this.name = machine.getCustomName(); + this.requests = machine.getInventoryByName("config"); + this.rowSize = machine.rowSize(); + this.rows = machine.rows(); + this.x = location.x; + this.y = location.y; + this.z = location.z; + this.dim = location.getDimension(); + this.side = machine.getSide(); + this.online = online; + this.inventoryNbt = new NBTTagList(); + updateNBT(); + } + + private void updateNBT() { + this.inventoryNbt = new NBTTagList(); + for (int i = 0; i < this.rows; ++i) { + for (int j = 0; j < this.rowSize; ++j) { + final int offset = this.rowSize * i; + ItemStack stack = this.requests.getStackInSlot(offset + j); + + if (stack != null) { + this.inventoryNbt.appendTag(stack.writeToNBT(new NBTTagCompound())); + } else { + this.inventoryNbt.appendTag(new NBTTagCompound()); + } + } + } + } + + } +} diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelWireless.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelWireless.java new file mode 100644 index 000000000..286b9921b --- /dev/null +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerLevelWireless.java @@ -0,0 +1,17 @@ +package com.glodblock.github.client.gui.container; + +import net.minecraft.entity.player.InventoryPlayer; + +import com.glodblock.github.inventory.item.IWirelessTerminal; + +public class ContainerLevelWireless extends ContainerLevelTerminal { + + public ContainerLevelWireless(InventoryPlayer ip, IWirelessTerminal monitorable) { + super(ip, monitorable); + } + + @Override + protected boolean isWirelessTerminal() { + return true; + } +} diff --git a/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java b/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java index 5d19f19ac..daf003f14 100644 --- a/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java +++ b/src/main/java/com/glodblock/github/client/textures/FCPartsTexture.java @@ -18,6 +18,9 @@ public enum FCPartsTexture { PartFluidPatternTerminal_Bright("pattern_terminal_bright"), PartFluidPatternTerminal_Dark("pattern_terminal_dark"), PartFluidPatternTerminal_Colored("pattern_terminal_medium"), + PartLevelTerminal_Bright("level_terminal_bright"), + PartLevelTerminal_Dark("level_terminal_dark"), + PartLevelTerminal_Colored("level_terminal_medium"), PartTerminalBroad("terminal_broad"), PartFluidImportBus("fluid_import_face"), PartFluidExportBus("fluid_export_face"), diff --git a/src/main/java/com/glodblock/github/common/Config.java b/src/main/java/com/glodblock/github/common/Config.java index 558f4195e..b8a74ddaf 100644 --- a/src/main/java/com/glodblock/github/common/Config.java +++ b/src/main/java/com/glodblock/github/common/Config.java @@ -20,6 +20,8 @@ public class Config { public static int packetSize; public static int packetRate; public static boolean replaceEC2; + public static int levelMaintainerMinTicks; + public static int levelMaintainerMaxTicks; public static void run() { loadCategory(); @@ -66,6 +68,12 @@ private static void loadProperty() { "Fluid Craft for AE2", true, "Set true to handle missing item mappings from EC2. Note to work properly, you must have all relevant parts."); + + levelMaintainerMinTicks = Config.get("LevelMaintainer", "minTick", 5, "Number on ticks for minimal request") + .getInt(); + levelMaintainerMaxTicks = Config.get("LevelMaintainer", "maxTick", 120, "Number on ticks for maximal request") + .getInt(); + if (Config.hasChanged()) Config.save(); } diff --git a/src/main/java/com/glodblock/github/common/item/ItemPartLevelTerminal.java b/src/main/java/com/glodblock/github/common/item/ItemPartLevelTerminal.java new file mode 100644 index 000000000..f951d862c --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemPartLevelTerminal.java @@ -0,0 +1,71 @@ +package com.glodblock.github.common.item; + +import static net.minecraft.client.gui.GuiScreen.isShiftKeyDown; + +import java.util.List; + +import javax.annotation.Nullable; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.parts.PartLevelTerminal; +import com.glodblock.github.common.tabs.FluidCraftingTabs; +import com.glodblock.github.util.NameConst; + +import appeng.api.AEApi; +import appeng.api.parts.IPartItem; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class ItemPartLevelTerminal extends FCBaseItem implements IPartItem { + + public ItemPartLevelTerminal() { + this.setMaxStackSize(64); + this.setUnlocalizedName(NameConst.ITEM_PART_LEVEL_TERMINAL); + AEApi.instance().partHelper().setItemBusRenderer(this); + } + + @Nullable + @Override + public PartLevelTerminal createPartFromItemStack(ItemStack is) { + return new PartLevelTerminal(is); + } + + @Override + public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, + float xOffset, float yOffset, float zOffset) { + return AEApi.instance().partHelper().placeBus(player.getHeldItem(), x, y, z, side, player, world); + } + + @Override + @SuppressWarnings("unchecked") + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, EntityPlayer player, List toolTip, boolean flag) { + if (isShiftKeyDown()) { + toolTip.add(NameConst.i18n(NameConst.TT_LEVEL_TERMINAL)); + } else { + toolTip.add(NameConst.i18n(NameConst.TT_SHIFT_FOR_MORE)); + } + } + + @Override + public ItemPartLevelTerminal register() { + GameRegistry.registerItem(this, NameConst.ITEM_PART_LEVEL_TERMINAL, FluidCraft.MODID); + setCreativeTab(FluidCraftingTabs.INSTANCE); + return this; + } + + @Override + public void registerIcons(IIconRegister _iconRegister) {} + + @Override + @SideOnly(Side.CLIENT) + public int getSpriteNumber() { + return 0; + } +} diff --git a/src/main/java/com/glodblock/github/common/item/ItemWirelessLevelTerminal.java b/src/main/java/com/glodblock/github/common/item/ItemWirelessLevelTerminal.java new file mode 100644 index 000000000..a762a1437 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemWirelessLevelTerminal.java @@ -0,0 +1,51 @@ +package com.glodblock.github.common.item; + +import java.util.EnumSet; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.tabs.FluidCraftingTabs; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.inventory.item.WirelessLevelTerminalInventory; +import com.glodblock.github.loader.IRegister; +import com.glodblock.github.util.NameConst; +import com.glodblock.github.util.Util; + +import appeng.api.AEApi; +import appeng.api.networking.IGridNode; +import appeng.core.features.AEFeature; +import appeng.core.localization.PlayerMessages; +import cpw.mods.fml.common.registry.GameRegistry; + +public class ItemWirelessLevelTerminal extends ItemBaseWirelessTerminal + implements IRegister { + + public ItemWirelessLevelTerminal() { + super(GuiType.WIRELESS_LEVEL_TERMINAL); + AEApi.instance().registries().wireless().registerWirelessHandler(this); + this.setFeature(EnumSet.of(AEFeature.WirelessAccessTerminal, AEFeature.PoweredTools)); + setUnlocalizedName(NameConst.ITEM_WIRELESS_LEVEL_TERMINAL); + setTextureName(FluidCraft.resource(NameConst.ITEM_WIRELESS_LEVEL_TERMINAL).toString()); + } + + @Override + public ItemWirelessLevelTerminal register() { + GameRegistry.registerItem(this, NameConst.ITEM_WIRELESS_LEVEL_TERMINAL, FluidCraft.MODID); + setCreativeTab(FluidCraftingTabs.INSTANCE); + return this; + } + + @Override + public Object getInventory(ItemStack stack, World world, int x, int y, int z, EntityPlayer player) { + try { + IGridNode gridNode = Util.getWirelessGrid(stack); + return new WirelessLevelTerminalInventory(stack, x, gridNode, player); + } catch (Exception e) { + player.addChatMessage(PlayerMessages.OutOfRange.get()); + } + return null; + } +} diff --git a/src/main/java/com/glodblock/github/common/item/ItemWirelessUltraTerminal.java b/src/main/java/com/glodblock/github/common/item/ItemWirelessUltraTerminal.java index 51807e85c..939799544 100644 --- a/src/main/java/com/glodblock/github/common/item/ItemWirelessUltraTerminal.java +++ b/src/main/java/com/glodblock/github/common/item/ItemWirelessUltraTerminal.java @@ -24,6 +24,7 @@ import com.glodblock.github.inventory.item.WirelessCraftingTerminalInventory; import com.glodblock.github.inventory.item.WirelessFluidTerminalInventory; import com.glodblock.github.inventory.item.WirelessInterfaceTerminalInventory; +import com.glodblock.github.inventory.item.WirelessLevelTerminalInventory; import com.glodblock.github.inventory.item.WirelessPatternTerminalExInventory; import com.glodblock.github.inventory.item.WirelessPatternTerminalInventory; import com.glodblock.github.loader.IRegister; @@ -63,6 +64,7 @@ public ItemWirelessUltraTerminal() { guis.add(GuiType.WIRELESS_FLUID_PATTERN_TERMINAL_EX); guis.add(GuiType.WIRELESS_FLUID_TERMINAL); guis.add(GuiType.WIRELESS_INTERFACE_TERMINAL); + guis.add(GuiType.WIRELESS_LEVEL_TERMINAL); if (ModAndClassUtil.ThE) { guis.add(GuiType.WIRELESS_ESSENTIA_TERMINAL); } @@ -115,6 +117,8 @@ public Object getInventory(ItemStack stack, World world, int x, int y, int z, En return new WirelessFluidTerminalInventory(stack, x, gridNode, player); } else if (gui == GuiType.WIRELESS_INTERFACE_TERMINAL) { return new WirelessInterfaceTerminalInventory(stack, x, gridNode, player); + } else if (gui == GuiType.WIRELESS_LEVEL_TERMINAL) { + return new WirelessLevelTerminalInventory(stack, x, gridNode, player); } else if (gui == GuiType.WIRELESS_FLUID_PATTERN_TERMINAL_EX) { return new WirelessPatternTerminalExInventory(stack, x, gridNode, player); } else { @@ -197,6 +201,15 @@ public static void switchTerminal(EntityPlayer player, GuiType guiType) { } } + public static boolean hasInfinityBoosterCard(EntityPlayer player) { + ImmutablePair term = Util.getUltraWirelessTerm(player); + if (term == null) return false; + if (term.getRight().getItem() instanceof ItemWirelessUltraTerminal) { + return Util.hasInfinityBoosterCard(term.getRight()); + } + return false; + } + public static List getGuis() { return guis; } diff --git a/src/main/java/com/glodblock/github/common/parts/PartFluidLevelEmitter.java b/src/main/java/com/glodblock/github/common/parts/PartFluidLevelEmitter.java index 3abab7199..147ed28fa 100644 --- a/src/main/java/com/glodblock/github/common/parts/PartFluidLevelEmitter.java +++ b/src/main/java/com/glodblock/github/common/parts/PartFluidLevelEmitter.java @@ -17,6 +17,7 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; +import com.glodblock.github.api.registries.ILevelViewable; import com.glodblock.github.common.item.ItemFluidPacket; import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; @@ -62,8 +63,8 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -public class PartFluidLevelEmitter extends PartUpgradeable - implements IStackWatcherHost, ICraftingWatcherHost, IMEMonitorHandlerReceiver, IGridTickable { +public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatcherHost, ICraftingWatcherHost, + IMEMonitorHandlerReceiver, IGridTickable, ILevelViewable { private static final int FLAG_ON = 8; diff --git a/src/main/java/com/glodblock/github/common/parts/PartLevelTerminal.java b/src/main/java/com/glodblock/github/common/parts/PartLevelTerminal.java new file mode 100644 index 000000000..7df1d9919 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/parts/PartLevelTerminal.java @@ -0,0 +1,83 @@ +package com.glodblock.github.common.parts; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import com.glodblock.github.client.textures.FCPartsTexture; +import com.glodblock.github.common.parts.base.FCPart; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.inventory.item.IClickableInTerminal; +import com.glodblock.github.util.Util; + +public class PartLevelTerminal extends FCPart implements IClickableInTerminal { + + private static final FCPartsTexture FRONT_BRIGHT_ICON = FCPartsTexture.PartLevelTerminal_Bright; + private static final FCPartsTexture FRONT_DARK_ICON = FCPartsTexture.PartLevelTerminal_Colored; + private static final FCPartsTexture FRONT_COLORED_ICON = FCPartsTexture.PartLevelTerminal_Dark; + + private Util.DimensionalCoordSide tile; + + public PartLevelTerminal(ItemStack is) { + super(is, true); + } + + @Override + public void readFromNBT(final NBTTagCompound data) { + super.readFromNBT(data); + if (data.hasKey("clickedInterface")) { + NBTTagCompound tileMsg = (NBTTagCompound) data.getTag("clickedInterface"); + this.tile = Util.DimensionalCoordSide.readFromNBT(tileMsg); + } + } + + @Override + public void writeToNBT(final NBTTagCompound data) { + super.writeToNBT(data); + if (this.tile == null) return; + + NBTTagCompound tileMsg = new NBTTagCompound(); + tile.writeToNBT(tileMsg); + data.setTag("clickedInterface", tileMsg); + } + + @Override + public FCPartsTexture getFrontBright() { + return FRONT_BRIGHT_ICON; + } + + @Override + public FCPartsTexture getFrontColored() { + return FRONT_COLORED_ICON; + } + + @Override + public FCPartsTexture getFrontDark() { + return FRONT_DARK_ICON; + } + + @Override + public boolean isLightSource() { + return false; + } + + @Override + public boolean isBooting() { + return super.isBooting(); + } + + @Override + public GuiType getGui() { + return GuiType.LEVEL_TERMINAL; + } + + @Override + public void setClickedInterface(Util.DimensionalCoordSide tile) { + this.tile = tile; + this.getHost().markForSave(); + } + + @Override + public Util.DimensionalCoordSide getClickedInterface() { + return this.tile; + } +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java b/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java index 733673a0e..9a9b1517a 100644 --- a/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/common/tile/TileLevelMaintainer.java @@ -1,11 +1,18 @@ package com.glodblock.github.common.tile; import java.util.concurrent.Future; +import java.util.function.UnaryOperator; import net.minecraft.inventory.IInventory; 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.Nullable; + +import com.glodblock.github.api.registries.ILevelViewable; +import com.glodblock.github.common.Config; import com.glodblock.github.common.item.ItemFluidDrop; import com.glodblock.github.inventory.AeItemStackHandler; import com.glodblock.github.inventory.AeStackInventory; @@ -37,7 +44,6 @@ import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; import appeng.core.AELog; -import appeng.crafting.CraftingLink; import appeng.helpers.NonNullArrayIterator; import appeng.me.GridAccessException; import appeng.tile.TileEvent; @@ -45,139 +51,151 @@ import appeng.tile.grid.AENetworkTile; import appeng.tile.inventory.IAEAppEngInventory; import appeng.tile.inventory.InvOperation; +import appeng.util.Platform; import appeng.util.item.AEItemStack; import io.netty.buffer.ByteBuf; public class TileLevelMaintainer extends AENetworkTile - implements IAEAppEngInventory, IGridTickable, ICraftingRequester, IPowerChannelState { + implements IAEAppEngInventory, IGridTickable, ICraftingRequester, IPowerChannelState, ILevelViewable { public static final int REQ_COUNT = 5; public final InventoryRequest requests = new InventoryRequest(this); private final BaseActionSource source; - private final IInventory inv = new AeItemStackHandler(requests.getRequestStacks()); + private final IInventory inv = new AeItemStackHandler(requests.requestStacks); private boolean isPowered = false; public TileLevelMaintainer() { getProxy().setIdlePowerUsage(1D); getProxy().setFlags(GridFlags.REQUIRE_CHANNEL); - this.source = new MachineSource(this); + source = new MachineSource(this); } public AeStackInventory getRequestSlots() { - return requests.getRequestStacks(); + return requests.requestStacks; } @Override public ImmutableSet getRequestedJobs() { - return ImmutableSet.copyOf(new NonNullArrayIterator<>(this.requests.getLinks())); - } - - private IAEItemStack setState(ICraftingLink link, IAEItemStack items) { - if (items != null) { - requests.setState(link, State.Exporting); - } else { - requests.setState(link, State.Crafting); - } - return items; + return ImmutableSet.copyOf(new NonNullArrayIterator<>(requests.links)); } @Override public IAEItemStack injectCraftedItems(ICraftingLink link, IAEItemStack items, Actionable mode) { + int idx = requests.getIdxByLink(link); try { - if (this.getProxy().isActive()) { - final IEnergyGrid energy = this.getProxy().getEnergy(); + if (getProxy().isActive()) { + final IEnergyGrid energy = getProxy().getEnergy(); final double power = Math .ceil(ItemFluidDrop.isFluidStack(items) ? items.getStackSize() / 1000D : items.getStackSize()); if (energy.extractAEPower(power, mode, PowerMultiplier.CONFIG) > power - 0.01) { if (ItemFluidDrop.isFluidStack(items)) { - IAEFluidStack notInserted = this.getProxy().getStorage().getFluidInventory() - .injectItems(ItemFluidDrop.getAeFluidStack(items), mode, this.source); - if (notInserted != null) { - items.setStackSize(notInserted.getStackSize()); - return setState(link, items); + IAEFluidStack notInjectedItems = getProxy().getStorage().getFluidInventory() + .injectItems(ItemFluidDrop.getAeFluidStack(items), mode, source); + if (notInjectedItems != null) { + items.setStackSize(notInjectedItems.getStackSize()); + requests.updateState(idx, State.Export); + + return items; } else { return null; } } else { - return setState( - link, - this.getProxy().getStorage().getItemInventory().injectItems(items, mode, this.source)); + return getProxy().getStorage().getItemInventory().injectItems(items, mode, source); } } } } catch (GridAccessException e) { AELog.debug(e); } - return setState(link, items); + + return items; } @Override public void jobStateChange(ICraftingLink link) { - if (this.requests.getLinks() != null) { - for (int x = 0; x < this.requests.getLinks().length; x++) { - if (this.requests.getLinks()[x] == link) { - this.requests.getLinks()[x] = link; - return; - } + for (int x = 0; x < REQ_COUNT; x++) { + if (requests.getLink(x) == link) { + requests.updateLink(x, link); + return; } } } @Override public TickingRequest getTickingRequest(IGridNode node) { - return new TickingRequest(5, 120, false, true); + return new TickingRequest(Config.levelMaintainerMinTicks, Config.levelMaintainerMaxTicks, false, true); } @Override public TickRateModulation tickingRequest(IGridNode node, int TicksSinceLastCall) { - return this.canDoBusWork() ? this.doWork() : TickRateModulation.IDLE; + return canDoBusWork() ? doWork() : TickRateModulation.IDLE; } private TickRateModulation doWork() { - if (!this.getProxy().isActive() || !this.canDoBusWork()) { + if (!getProxy().isActive() || !canDoBusWork()) { return TickRateModulation.IDLE; } - boolean didSomething = false; try { - ICraftingGrid cg = this.getProxy().getCrafting(); - IGrid grid = this.getProxy().getGrid(); - final IItemList inv = this.getProxy().getStorage().getItemInventory().getStorageList(); + final ICraftingGrid craftingGrid = getProxy().getCrafting(); + final IGrid grid = getProxy().getGrid(); + final IItemList inv = getProxy().getStorage().getItemInventory().getStorageList(); for (int i = 0; i < REQ_COUNT; i++) { - IAEItemStack is = requests.getRequestQtyStack(i); - if (is != null && requests.getBatchSize(i) > 0) { + long quantity = requests.getQuantity(i); + long batchSize = requests.getBatchSize(i); + boolean isEnable = requests.isEnable(i); + if (!isEnable || batchSize == 0) requests.updateState(i, State.None); + if (batchSize > 0) { IAEItemStack craftItem = requests.getCraftItem(i); - if (this.requests.isDone(i)) this.requests.setState(i, State.Idling); - if (cg.canEmitFor(craftItem) || cg.isRequesting(craftItem) - || inv.findPrecise(is) == null - || !inv.findPrecise(is).isCraftable() - || inv.findPrecise(is).getStackSize() >= is.getStackSize() - || !this.requests.isDone(i)) + IAEItemStack aeItem = inv.findPrecise(craftItem); + boolean isDone = requests.isDone(i); + boolean isCraftable = aeItem != null && aeItem.isCraftable(); + boolean shouldCraft = isCraftable && aeItem.getStackSize() < quantity; + if (isDone) requests.updateState(i, State.Idle); + if (!isCraftable) requests.updateState(i, State.Error); + if (craftingGrid.canEmitFor(craftItem) || craftingGrid.isRequesting(craftItem) + || !isDone + || !shouldCraft) continue; // do crafting - Future jobTask = requests.getJobs()[i]; + Future jobTask = requests.getJob(i); if (jobTask == null) { - requests.getJobs()[i] = cg.beginCraftingJob(getWorldObj(), grid, this.source, craftItem, null); + requests.updateJob( + i, + craftingGrid.beginCraftingJob(getWorldObj(), grid, source, craftItem, null)); + requests.updateState(i, State.Craft); + + // calculate only one job per tick request + return TickRateModulation.SAME; } else if (jobTask.isDone()) { - requests.setState(i, State.Idling); + requests.updateState(i, State.Craft); try { ICraftingJob job = jobTask.get(); if (job != null) { - ICraftingLink link = cg.submitJob(job, this, null, false, this.source); - requests.jobs[i] = null; + ICraftingLink link = craftingGrid.submitJob(job, this, null, false, source); + requests.updateJob(i, null); if (link != null) { - didSomething = true; - requests.setState(i, State.Crafting); - requests.getLinks()[i] = link; + requests.updateState(i, State.Craft); + requests.updateLink(i, link); + + // submit only one job per tick request + return TickRateModulation.SAME; + } else { + requests.updateState(i, State.Error); } + } else { + requests.updateState(i, State.Error); } } catch (Exception ignored) { - + requests.updateState(i, State.Error); } } } } - } catch (final GridAccessException ignore) {} - return didSomething ? TickRateModulation.FASTER : TickRateModulation.SLOWER; + } catch (final GridAccessException ignore) { + + } + + return TickRateModulation.SAME; } @Override @@ -196,7 +214,7 @@ public void onChangeInventory(IInventory inv, int slot, InvOperation mc, ItemSta } protected boolean canDoBusWork() { - return this.getProxy().isActive(); + return getProxy().isActive(); } @Override @@ -204,275 +222,398 @@ public void gridChanged() {} @Override public boolean isPowered() { - return this.isPowered; + return isPowered; } @Override public boolean isActive() { - return this.isPowered; + return isPowered; } public InventoryRequest getRequestInventory() { - return this.requests; + return requests; } public IInventory getInventory() { return inv; } + public IInventory getInventoryByName(String name) { + if (name == "config") return new AeItemStackHandler(requests.requestStacks); + + return null; + } + public void updateQuantity(int idx, long size) { - this.requests.updateQuantity(idx, size); + requests.updateQuantity(idx, size); } public void updateBatchSize(int idx, long size) { - this.requests.updateBatchSize(idx, size); + requests.updateBatchSize(idx, size); } - public void setRequestStatus(int idx, boolean enable) { - this.requests.setEnable(idx, enable); + public void updateStatus(int idx, boolean enable) { + requests.updateStatus(idx, enable); } private void readLinkFromNBT(NBTTagCompound data) { + for (int i = 0; i < REQ_COUNT; i++) { + final NBTTagCompound stackData = requests.getItemStack(i).getTagCompound(); + if (stackData != null && stackData.hasNoTags() + && !stackData.hasKey(TLMTags.Link.tagName) + && stackData.getCompoundTag(TLMTags.Link.tagName).hasNoTags()) { + requests.updateLink(i, null); + requests.updateState(i, State.Idle); + } else { + NBTTagCompound linkData = stackData.getCompoundTag(TLMTags.Link.tagName); + requests.updateLink(i, AEApi.instance().storage().loadCraftingLink(linkData, this)); + if (!requests.isDone(i)) requests.updateState(i, State.Craft); + } + } + } + + /** + * @deprecated + */ + @Deprecated + private void readLinkFromNBT__old(NBTTagCompound data) { try { - for (int i = 0; i < this.requests.getLinks().length; i++) { + for (int i = 0; i < REQ_COUNT; i++) { final NBTTagCompound link = data.getCompoundTag("links-" + i); if (link != null && link.hasNoTags()) { - this.requests.getLinks()[i] = null; + requests.updateLink(i, null); } else { - this.requests.getLinks()[i] = AEApi.instance().storage().loadCraftingLink(link, this); - if (!this.requests.isDone(i)) this.requests.setState(i, State.Crafting); + requests.updateLink(i, AEApi.instance().storage().loadCraftingLink(link, this)); + if (!requests.isDone(i)) requests.updateState(i, State.Craft); } } } catch (Exception ignore) {} } - private NBTTagCompound writeLinkToNBT(NBTTagCompound data) { - for (int i = 0; i < this.requests.getLinks().length; i++) { - if (this.requests.getLinks()[i] != null) { - CraftingLink link = (CraftingLink) this.requests.getLinks()[i]; - NBTTagCompound linkData = new NBTTagCompound(); - link.writeToNBT(linkData); - data.setTag("links-" + i, linkData); + @TileEvent(TileEventType.WORLD_NBT_WRITE) + public void writeToNBTEvent(NBTTagCompound data) { + requests.requestStacks.writeToNbt(data, TLMTags.RequestStacks.tagName); + } + + @TileEvent(TileEventType.WORLD_NBT_READ) + public void readFromNBTEvent(NBTTagCompound data) { + if (data.hasKey(TLMTags.RequestStacks.tagName)) { + requests.requestStacks.readFromNbt(data, TLMTags.RequestStacks.tagName); + if (Platform.isServer()) { + for (int i = 0; i < REQ_COUNT; i++) { + if (requests.requestStacks.getStack(i) != null) { + ItemStack storageStack = requests.requestStacks.getStack(i).getItemStack(); + ItemStack itemStack = loadItemStackFromTag(storageStack); + ItemStack craftStack = removeRecursion(storageStack); + if (!ItemStack.areItemStacksEqual(itemStack, craftStack)) { + requests.updateStack(i, craftStack); + AELog.info( + "[TileLevelMaintainer] Replace craft stack from: " + itemStack.toString() + + ":" + + (itemStack.hasTagCompound() ? itemStack.getTagCompound() : "{no tags}") + + "; with: " + + craftStack + + ":" + + (craftStack.hasTagCompound() ? craftStack.getTagCompound() + : "{no tags}")); + } + } + } } + } else { + // Migration from old data storage + long[] batches = new long[REQ_COUNT]; + long[] quantyties = new long[REQ_COUNT]; + requests.requestStacks.readFromNbt(data, "Batch"); + for (int i = 0; i < REQ_COUNT; i++) { + IAEItemStack batchStack = requests.requestStacks.getStack(i); + batches[i] = batchStack != null ? batchStack.getStackSize() : 0; + } + requests.requestStacks.readFromNbt(data, "Count"); + for (int i = 0; i < REQ_COUNT; i++) { + IAEItemStack quantityStack = requests.requestStacks.getStack(i); + quantyties[i] = quantityStack != null ? quantityStack.getStackSize() : 0; + } + requests.requestStacks.readFromNbt(data, "Inventory"); + for (int i = 0; i < REQ_COUNT; i++) { + IAEItemStack requestsStack = requests.requestStacks.getStack(i); + if (requestsStack != null) { + requests.updateStack(i, requestsStack.getItemStack()); + requests.updateBatchSize(i, batches[i]); + requests.updateQuantity(i, quantyties[i]); + } + } + readLinkFromNBT__old(data); } - return data; } - @TileEvent(TileEventType.WORLD_NBT_WRITE) - public NBTTagCompound writeToNBTEvent(NBTTagCompound data) { - this.requests.requestStacks.writeToNbt(data, "Inventory"); - this.requests.requestBatches.writeToNbt(data, "Batch"); - this.requests.requestQtys.writeToNbt(data, "Count"); - return writeLinkToNBT(data); + private ItemStack removeRecursion(ItemStack itemStack) { + if (itemStack.hasTagCompound() && itemStack.getTagCompound().hasKey(TLMTags.Stack.tagName)) { + return removeRecursion(loadItemStackFromTag(itemStack)); + } + return itemStack; } - @TileEvent(TileEventType.WORLD_NBT_READ) - public void readFromNBTEvent(NBTTagCompound data) { - this.requests.requestStacks.readFromNbt(data, "Inventory"); - this.requests.requestBatches.readFromNbt(data, "Batch"); - this.requests.requestQtys.readFromNbt(data, "Count"); - this.readLinkFromNBT(data); + @Nullable + private static ItemStack loadItemStackFromTag(ItemStack itemStack) { + return ItemStack.loadItemStackFromNBT(itemStack.getTagCompound().getCompoundTag(TLMTags.Stack.tagName)); } @TileEvent(TileEventType.NETWORK_READ) public boolean readFromStream(final ByteBuf data) { - final boolean oldPower = this.isPowered; - this.isPowered = data.readBoolean(); - return this.isPowered != oldPower; + final boolean oldPower = isPowered; + isPowered = data.readBoolean(); + return isPowered != oldPower; } @TileEvent(TileEventType.NETWORK_WRITE) public void writeToStream(final ByteBuf data) { - data.writeBoolean(this.isActive()); + data.writeBoolean(isActive()); } @MENetworkEventSubscribe public void stateChange(final MENetworkPowerStatusChange p) { - this.updatePowerState(); + updatePowerState(); } @MENetworkEventSubscribe public final void bootingRender(final MENetworkBootingStatusChange c) { - this.updatePowerState(); + updatePowerState(); } private void updatePowerState() { boolean newState = false; try { - newState = this.getProxy().isActive() - && this.getProxy().getEnergy().extractAEPower(1, Actionable.SIMULATE, PowerMultiplier.CONFIG) - > 0.0001; + newState = getProxy().isActive() + && getProxy().getEnergy().extractAEPower(1, Actionable.SIMULATE, PowerMultiplier.CONFIG) > 0.0001; } catch (final GridAccessException ignored) { } - if (newState != this.isPowered) { - this.isPowered = newState; - this.markForUpdate(); + if (newState != isPowered) { + isPowered = newState; + markForUpdate(); } } + @Override + public TileEntity getTile() { + return this; + } + + @Override + public ForgeDirection getSide() { + return ForgeDirection.UNKNOWN; + } + + @Override + public int rowSize() { + return REQ_COUNT; + } + + @Override + public ItemStack getSelfItemStack() { + return getItemFromTile(this); + } + public enum State { - Nothing, - Idling, - Crafting, - Exporting + None, + Idle, + Craft, + Export, + Error + } + + public enum TLMTags { + + RequestStacks("RequestStacks"), + Enable("Enable"), + Quantity("Quantity"), + Batch("Batch"), + Link("Link"), + State("State"), + Index("Index"), + Stack("Stack"); + + public final String tagName; + + TLMTags(String tagName) { + this.tagName = tagName; + } } - public static class InventoryRequest { + public static final class InventoryRequest { private final AeStackInventoryImpl requestStacks; - private final AeStackInventoryImpl requestBatches; - private final AeStackInventoryImpl requestQtys; private final Future[] jobs; private final ICraftingLink[] links; private final State[] state = new State[REQ_COUNT]; @SuppressWarnings("unchecked") public InventoryRequest(TileLevelMaintainer tile) { - this.requestStacks = new AeStackInventoryImpl<>(StorageChannel.ITEMS, REQ_COUNT, tile); - this.requestBatches = new AeStackInventoryImpl<>(StorageChannel.ITEMS, REQ_COUNT, tile); - this.requestQtys = new AeStackInventoryImpl<>(StorageChannel.ITEMS, REQ_COUNT, tile); - this.jobs = new Future[REQ_COUNT]; - this.links = new ICraftingLink[REQ_COUNT]; - } - - public void setEnable(int idx, boolean enable) { - IAEItemStack ias = this.getRequestStacks().getStack(idx); - IAEItemStack ias1 = this.getRequestBatches().getStack(idx); - if (ias != null && ias1 != null) { - ItemStack is = ias1.getItemStack(); - NBTTagCompound data = new NBTTagCompound(); - data.setBoolean("Enable", enable); - is.setTagCompound(data); - IAEItemStack i = AEItemStack.create(is); - i.setStackSize(ias1.getStackSize()); - this.getRequestBatches().setStack(idx, i); - } + requestStacks = new AeStackInventoryImpl<>(StorageChannel.ITEMS, REQ_COUNT, tile); + jobs = new Future[REQ_COUNT]; + links = new ICraftingLink[REQ_COUNT]; } public State getState(int idx) { - IAEItemStack ias = this.getRequestStacks().getStack(idx); + IAEItemStack ias = requestStacks.getStack(idx); if (ias == null) { - return State.Nothing; + return State.None; } else { - return this.state[idx] == null ? State.Idling : this.state[idx]; + return state[idx] == null ? State.Idle : state[idx]; } } - public void setState(ICraftingLink link, State state) { - int i = 0; - for (ICraftingLink link1 : this.getLinks()) { - if (link == link1) { - this.setState(i, state); - break; + public int getIdxByLink(ICraftingLink link) { + for (int i = 0; i < REQ_COUNT; i++) { + if (links[i] == link) { + return i; } - i++; } - } - - public void setState(int idx, State state) { - this.state[idx] = state; + return 0; } public boolean isEnable(int idx) { - IAEItemStack ias = this.getRequestBatches().getStack(idx); - if (ias != null) { - ItemStack is = ias.getItemStack(); - try { - return is.getTagCompound().getBoolean("Enable"); - } catch (NullPointerException e) { - // support old version - return true; - } - } else { + IAEItemStack ias = requestStacks.getStack(idx); + if (ias == null) { return true; } + + ItemStack is = ias.getItemStack(); + return is.hasTagCompound() ? is.getTagCompound().getBoolean(TLMTags.Enable.tagName) : true; } public boolean isDone(int index) { - if (this.getLinks()[index] != null) { - return this.getLinks()[index].isDone() || this.getLinks()[index].isCanceled(); + if (links[index] == null) { + return true; } - return true; + return links[index].isDone() || links[index].isCanceled(); } - public Future[] getJobs() { - return this.jobs; + public Future getJob(int idx) { + return jobs[idx]; } - public ICraftingLink[] getLinks() { - return links; + public ICraftingLink getLink(int idx) { + return links[idx]; } - public AeStackInventory getRequestQtys() { - return this.requestQtys; + public void updateJob(int idx, Future job) { + jobs[idx] = job; } - public AeStackInventory getRequestBatches() { - return this.requestBatches; + private void updateField(int idx, UnaryOperator updater) { + IAEItemStack ias = requestStacks.getStack(idx); + if (ias == null) return; + + ItemStack itemStack = ias.getItemStack(); + NBTTagCompound data = itemStack.hasTagCompound() ? itemStack.getTagCompound() : new NBTTagCompound(); + data.setInteger(TLMTags.Index.tagName, idx); + itemStack.setTagCompound(updater.apply(data)); + IAEItemStack newRequestStack = AEItemStack.create(itemStack); + newRequestStack.setStackSize(ias.getStackSize()); + requestStacks.setStack(idx, newRequestStack); + } - public AeStackInventory getRequestStacks() { - return this.requestStacks; + public void updateLink(int idx, ICraftingLink link) { + links[idx] = link; + + updateField(idx, data -> { + NBTTagCompound linkData = new NBTTagCompound(); + if (link != null) link.writeToNBT(linkData); + data.setTag(TLMTags.Link.tagName, linkData); + + return data; + }); } - public void updateQuantity(int idx, long size) { - IAEItemStack is = this.getRequestStacks().getStack(idx); - if (is != null) { - IAEItemStack i = is.copy(); - i.setStackSize(size); - this.getRequestQtys().setStack(idx, i); - } + public void updateState(int idx, State nextState) { + state[idx] = nextState; + + updateField(idx, data -> { + data.setInteger(TLMTags.State.tagName, nextState.ordinal()); + + return data; + }); } - public void updateBatchSize(int idx, long size) { - IAEItemStack ias = this.getRequestStacks().getStack(idx); - if (ias != null) { - ItemStack is = ias.copy().getItemStack(); - NBTTagCompound data = new NBTTagCompound(); - data.setBoolean("Enable", true); - is.setTagCompound(data); - IAEItemStack i = AEItemStack.create(is); - i.setStackSize(size); - this.getRequestBatches().setStack(idx, i); - } + public void updateStatus(int idx, boolean enable) { + updateField(idx, data -> { + State nextState = enable ? State.Idle : State.None; + + data.setBoolean(TLMTags.Enable.tagName, enable); + data.setInteger(TLMTags.State.tagName, nextState.ordinal()); + return data; + }); } - public IAEItemStack getRequestQtyStack(int idx) { - IAEItemStack is = this.getRequestStacks().getStack(idx); - if (is == null) return null; - IAEItemStack qis = this.getRequestQtys().getStack(idx); - if (qis == null || !is.isSameType(qis)) return null; - return this.getRequestQtys().getStack(idx); + public void updateQuantity(int idx, long quantity) { + updateField(idx, data -> { + data.setLong(TLMTags.Quantity.tagName, quantity); + + return data; + }); + } + + public void updateBatchSize(int idx, long batch) { + updateField(idx, data -> { + data.setLong(TLMTags.Batch.tagName, batch); + data.setBoolean(TLMTags.Enable.tagName, true); + + return data; + }); + } + + public void updateStack(int idx, ItemStack itemStack) { + updateField(idx, data -> { + NBTTagCompound stackData = new NBTTagCompound(); + if (itemStack != null) itemStack.writeToNBT(stackData); + data.setTag(TLMTags.Stack.tagName, stackData); + + return data; + }); + } + + public IAEItemStack getAEItemStack(int idx) { + return requestStacks.getStack(idx); + } + + public ItemStack getItemStack(int idx) { + return requestStacks.getStack(idx).getItemStack(); } public long getQuantity(int idx) { - IAEItemStack ias = this.getRequestQtyStack(idx); - if (ias == null) { - return 0; - } - return ias.getStackSize(); + if (!isEnable(idx)) return 0; + IAEItemStack ias = requestStacks.getStack(idx); + if (ias == null) return 0; + ItemStack itemStack = ias.getItemStack(); + if (!itemStack.hasTagCompound()) return 0; + + return itemStack.getTagCompound().getLong(TLMTags.Quantity.tagName); } public long getBatchSize(int idx) { - if (!this.isEnable(idx)) return 0; - IAEItemStack is = this.getRequestStacks().getStack(idx); - IAEItemStack is1 = this.getRequestBatches().getStack(idx); - if (is != null && is1 != null) { - return is1.getStackSize(); - } - return 0; + if (!isEnable(idx)) return 0; + IAEItemStack ias = requestStacks.getStack(idx); + if (ias == null) return 0; + ItemStack itemStack = ias.getItemStack(); + if (!itemStack.hasTagCompound()) return 0; + + return itemStack.getTagCompound().getLong(TLMTags.Batch.tagName); } public IAEItemStack getCraftItem(int idx) { - IAEItemStack is = this.getRequestQtyStack(idx); - if (is != null) { - IAEItemStack ias = is.copy(); - ias.setStackSize(this.getBatchSize(idx)); - return ias; - } - return null; + IAEItemStack is = requestStacks.getStack(idx); + if (is == null) return null; + if (is.getItemStack() == null) return null; + ItemStack qis = loadItemStackFromTag(is.getItemStack()); + if (qis == null) return null; + IAEItemStack qais = AEItemStack.create(qis); + qais.setStackSize(getBatchSize(idx)); + + return qais; } } } diff --git a/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java b/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java index 6d38d376f..f43c8ebf6 100644 --- a/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java +++ b/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java @@ -11,8 +11,7 @@ import com.glodblock.github.coremod.transform.DualityInterfaceTransformer; import com.glodblock.github.coremod.transform.ExternalStorageRegistryTransformer; import com.glodblock.github.coremod.transform.GuiCraftingTransformer; -import com.glodblock.github.coremod.transform.NEITransfermer; -import com.glodblock.github.coremod.transform.PacketCompressedNBTTransformer; +import com.glodblock.github.coremod.transform.NEITransformer; public class FCClassTransformer implements IClassTransformer { @@ -24,9 +23,8 @@ public byte[] transform(String name, String transformedName, byte[] code) { case "appeng.me.cluster.implementations.CraftingCPUCluster" -> tform = CraftingCpuTransformer.INSTANCE; case "appeng.helpers.DualityInterface" -> tform = DualityInterfaceTransformer.INSTANCE; case "appeng.client.gui.implementations.GuiCraftingCPU", "appeng.client.gui.implementations.GuiCraftConfirm", "net.p455w0rd.wirelesscraftingterminal.client.gui.GuiCraftConfirm", "appeng.client.gui.widgets.GuiCraftingTree" -> tform = GuiCraftingTransformer.INSTANCE; - case "appeng.integration.modules.NEI" -> tform = NEITransfermer.INSTANCE; + case "appeng.integration.modules.NEI" -> tform = NEITransformer.INSTANCE; case "appeng.core.features.registries.ExternalStorageRegistry" -> tform = ExternalStorageRegistryTransformer.INSTANCE; - case "appeng.core.sync.packets.PacketCompressedNBT" -> tform = PacketCompressedNBTTransformer.INSTANCE; default -> { return code; } diff --git a/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooks.java b/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooks.java index 69ca8afe5..3a3f63f5a 100644 --- a/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooks.java +++ b/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooks.java @@ -33,6 +33,7 @@ import appeng.api.storage.IMEInventory; import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEItemStack; +import appeng.client.gui.IGuiTooltipHandler; import appeng.crafting.MECraftingInventory; import appeng.me.MachineSet; import appeng.me.cluster.implementations.CraftingCPUCluster; @@ -176,15 +177,15 @@ public static void storeFluidItem(CraftingCPUCluster instance) { } public static ItemStack getStackUnderMouse(GuiContainer gui, int mousex, int mousey) { - if (gui instanceof GuiFluidCraftConfirm) { - return ((GuiFluidCraftConfirm) gui).getHoveredStack(); + if (gui instanceof IGuiTooltipHandler guiTooltipHandler) { + return guiTooltipHandler.getHoveredStack(); } return null; } public static boolean shouldShowTooltip(GuiContainer gui) { - if (gui instanceof GuiFluidCraftConfirm) { - return ((GuiFluidCraftConfirm) gui).getHoveredStack() == null; + if (gui instanceof GuiFluidCraftConfirm guiCraftConfirm) { + return guiCraftConfirm.getHoveredStack() == null; } return true; } diff --git a/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooksClient.java b/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooksClient.java index 4cd9db062..bf94e47fb 100644 --- a/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooksClient.java +++ b/src/main/java/com/glodblock/github/coremod/hooker/CoreModHooksClient.java @@ -1,22 +1,9 @@ package com.glodblock.github.coremod.hooker; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.nbt.NBTTagCompound; - -import com.glodblock.github.client.gui.GuiInterfaceTerminalWireless; - import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class CoreModHooksClient { - public static void clientPacketData(NBTTagCompound data) { - GuiScreen gs = Minecraft.getMinecraft().currentScreen; - if (gs instanceof GuiInterfaceTerminalWireless) { - ((GuiInterfaceTerminalWireless) gs).postUpdate(data); - } - } - } diff --git a/src/main/java/com/glodblock/github/coremod/registries/LevelTerminalRegistry.java b/src/main/java/com/glodblock/github/coremod/registries/LevelTerminalRegistry.java new file mode 100644 index 000000000..326cda9d4 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/registries/LevelTerminalRegistry.java @@ -0,0 +1,71 @@ +package com.glodblock.github.coremod.registries; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import com.glodblock.github.api.registries.ILevelTerminalRegistry; +import com.glodblock.github.api.registries.ILevelViewable; +import com.glodblock.github.api.registries.ILevelViewableAdapter; +import com.glodblock.github.common.parts.PartFluidLevelEmitter; +import com.glodblock.github.common.tile.TileLevelMaintainer; +import com.glodblock.github.coremod.registries.adapters.PartFluidLevelEmitterAdapter; +import com.glodblock.github.coremod.registries.adapters.PartLevelEmitterAdapter; + +import appeng.api.networking.IGridHost; +import appeng.parts.automation.PartLevelEmitter; + +public class LevelTerminalRegistry implements ILevelTerminalRegistry { + + private final Set> supportedClasses = new HashSet<>(); + private final Map, Class> adapterMap = new WeakHashMap<>(); + private final Map, ILevelViewableAdapter> adapterInstanceMap = new WeakHashMap<>(); + + private static class Singleton { + + private static final ILevelTerminalRegistry INSTANCE = new LevelTerminalRegistry(); + } + + { + this.register(TileLevelMaintainer.class); + this.register(PartFluidLevelEmitter.class, new PartFluidLevelEmitterAdapter()); + this.register(PartLevelEmitter.class, new PartLevelEmitterAdapter()); + } + + public Set> getSupportedClasses() { + return supportedClasses; + } + + @Override + public boolean isAdopted(Class clazz) { + return adapterMap.containsKey(clazz); + } + + @Override + public Class getAdopted(Class clazz) { + return adapterMap.getOrDefault(clazz, null); + } + + @Override + public ILevelViewableAdapter getAdapter(Class clazz) { + return adapterInstanceMap.getOrDefault(clazz, null); + } + + public static ILevelTerminalRegistry instance() { + return Singleton.INSTANCE; + } + + @Override + public void register(Class clazz) { + supportedClasses.add(clazz); + } + + @Override + public void register(Class aeClass, ILevelViewableAdapter adapter) { + var aClass = adapter.getClass(); + supportedClasses.add(aClass); + adapterMap.put(aClass, aeClass); + adapterInstanceMap.put(aClass, adapter); + } +} diff --git a/src/main/java/com/glodblock/github/coremod/registries/adapters/PartFluidLevelEmitterAdapter.java b/src/main/java/com/glodblock/github/coremod/registries/adapters/PartFluidLevelEmitterAdapter.java new file mode 100644 index 000000000..b8aad794b --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/registries/adapters/PartFluidLevelEmitterAdapter.java @@ -0,0 +1,88 @@ +package com.glodblock.github.coremod.registries.adapters; + +import static com.glodblock.github.coremod.registries.adapters.PartLevelEmitterAdapter.getPatchedInventory; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +import com.glodblock.github.api.registries.ILevelViewable; +import com.glodblock.github.api.registries.ILevelViewableAdapter; +import com.glodblock.github.common.parts.PartFluidLevelEmitter; +import com.glodblock.github.common.tile.TileLevelMaintainer.State; + +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.util.AECableType; +import appeng.api.util.DimensionalCoord; + +public class PartFluidLevelEmitterAdapter implements ILevelViewable, ILevelViewableAdapter { + + private PartFluidLevelEmitter delegate; + + public PartFluidLevelEmitterAdapter() {} + + public ILevelViewable adapt(IGridHost gridHost) { + if (gridHost instanceof PartFluidLevelEmitter levelEmitter) this.delegate = levelEmitter; + return this; + }; + + @Override + public DimensionalCoord getLocation() { + return delegate.getLocation(); + } + + @Override + public TileEntity getTile() { + return delegate.getTile(); + } + + @Override + public ForgeDirection getSide() { + return delegate.getSide(); + } + + @Override + public IInventory getInventoryByName(String name) { + long value = delegate.getReportingValue(); + State state = delegate.isProvidingStrongPower() > 0 ? State.Craft : State.Idle; + + return getPatchedInventory(delegate.getInventoryByName(name), value, state); + } + + @Override + public IGridNode getGridNode(ForgeDirection dir) { + return delegate.getGridNode(dir); + } + + @Override + public AECableType getCableConnectionType(ForgeDirection dir) { + return delegate.getCableConnectionType(dir); + } + + @Override + public void securityBreak() { + delegate.securityBreak(); + } + + @Override + public String getCustomName() { + return delegate.getCustomName(); + } + + @Override + public boolean hasCustomName() { + return delegate.hasCustomName(); + } + + @Override + public void setCustomName(String name) { + delegate.hasCustomName(); + } + + @Override + public ItemStack getSelfItemStack() { + return delegate.getItemStack(); + } +} diff --git a/src/main/java/com/glodblock/github/coremod/registries/adapters/PartLevelEmitterAdapter.java b/src/main/java/com/glodblock/github/coremod/registries/adapters/PartLevelEmitterAdapter.java new file mode 100644 index 000000000..cf4cd2556 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/registries/adapters/PartLevelEmitterAdapter.java @@ -0,0 +1,117 @@ +package com.glodblock.github.coremod.registries.adapters; + +import net.minecraft.inventory.IInventory; +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 com.glodblock.github.api.registries.ILevelViewable; +import com.glodblock.github.api.registries.ILevelViewableAdapter; +import com.glodblock.github.common.tile.TileLevelMaintainer.State; +import com.glodblock.github.common.tile.TileLevelMaintainer.TLMTags; +import com.glodblock.github.inventory.AeItemStackHandler; +import com.glodblock.github.inventory.AeStackInventoryImpl; + +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.AECableType; +import appeng.api.util.DimensionalCoord; +import appeng.parts.automation.PartLevelEmitter; +import appeng.util.item.AEItemStack; + +public class PartLevelEmitterAdapter implements ILevelViewable, ILevelViewableAdapter { + + private PartLevelEmitter delegate; + + private static final int SLOT_IN = 0; + + public PartLevelEmitterAdapter() {} + + public ILevelViewable adapt(IGridHost gridHost) { + if (gridHost instanceof PartLevelEmitter levelEmitter) this.delegate = levelEmitter; + return this; + } + + @NotNull + static public IInventory getPatchedInventory(IInventory inventory, long quantity, State state) { + ItemStack itemStack = inventory.getStackInSlot(SLOT_IN); + if (itemStack == null) return inventory; + NBTTagCompound data = !itemStack.hasTagCompound() ? new NBTTagCompound() : itemStack.getTagCompound(); + data.setLong(TLMTags.Quantity.tagName, quantity); + data.setInteger(TLMTags.State.tagName, state.ordinal()); + itemStack.setTagCompound(data); + + AeStackInventoryImpl inv = new AeStackInventoryImpl<>(StorageChannel.ITEMS, 1); + inv.setStack(SLOT_IN, AEItemStack.create(itemStack)); + + return new AeItemStackHandler(inv); + } + + @Override + public DimensionalCoord getLocation() { + return delegate.getLocation(); + } + + @Override + public TileEntity getTile() { + return delegate.getTile(); + } + + @Override + public IInventory getInventoryByName(String name) { + long value = delegate.getReportingValue(); + State state = delegate.isProvidingStrongPower() > 0 ? State.Craft : State.Idle; + + return getPatchedInventory(delegate.getInventoryByName(name), value, state); + } + + @Override + public IGridNode getGridNode(ForgeDirection dir) { + return delegate.getGridNode(dir); + } + + @Override + public AECableType getCableConnectionType(ForgeDirection dir) { + return delegate.getCableConnectionType(dir); + } + + @Override + public ForgeDirection getSide() { + return delegate.getSide(); + } + + @Override + public void securityBreak() { + delegate.securityBreak(); + } + + @Override + public String getCustomName() { + return delegate.getCustomName(); + } + + @Override + public boolean hasCustomName() { + return delegate.hasCustomName(); + } + + @Override + public void setCustomName(String name) { + delegate.hasCustomName(); + } + + @Override + public ItemStack getSelfItemStack() { + return delegate.getItemStack(); + } + + @Override + public ItemStack getDisplayItemStack() { + return delegate.getCrafterIcon(); + } +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/NEITransfermer.java b/src/main/java/com/glodblock/github/coremod/transform/NEITransformer.java similarity index 94% rename from src/main/java/com/glodblock/github/coremod/transform/NEITransfermer.java rename to src/main/java/com/glodblock/github/coremod/transform/NEITransformer.java index f7441a807..4a596367e 100644 --- a/src/main/java/com/glodblock/github/coremod/transform/NEITransfermer.java +++ b/src/main/java/com/glodblock/github/coremod/transform/NEITransformer.java @@ -6,11 +6,11 @@ import com.glodblock.github.coremod.FCClassTransformer; -public class NEITransfermer extends FCClassTransformer.ClassMapper { +public class NEITransformer extends FCClassTransformer.ClassMapper { - public static final NEITransfermer INSTANCE = new NEITransfermer(); + public static final NEITransformer INSTANCE = new NEITransformer(); - private NEITransfermer() { + private NEITransformer() { // NO-OP } diff --git a/src/main/java/com/glodblock/github/coremod/transform/PacketCompressedNBTTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/PacketCompressedNBTTransformer.java deleted file mode 100644 index 0d92f73a3..000000000 --- a/src/main/java/com/glodblock/github/coremod/transform/PacketCompressedNBTTransformer.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.glodblock.github.coremod.transform; - -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -import com.glodblock.github.coremod.FCClassTransformer; - -public class PacketCompressedNBTTransformer extends FCClassTransformer.ClassMapper { - - public static final PacketCompressedNBTTransformer INSTANCE = new PacketCompressedNBTTransformer(); - - private PacketCompressedNBTTransformer() { - // NO-OP - } - - @Override - protected ClassVisitor getClassMapper(ClassVisitor downstream) { - return new TransformPacketCompressedNBT(Opcodes.ASM5, downstream); - } - - private static class TransformPacketCompressedNBT extends ClassVisitor { - - TransformPacketCompressedNBT(int api, ClassVisitor cv) { - super(api, cv); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (name.equals("clientPacketData")) { - return new TransformClientPacketData(api, super.visitMethod(access, name, desc, signature, exceptions)); - } - return super.visitMethod(access, name, desc, signature, exceptions); - - } - } - - private static class TransformClientPacketData extends MethodVisitor { - - TransformClientPacketData(int api, MethodVisitor mv) { - super(api, mv); - } - - @Override - public void visitInsn(int opcode) { - super.visitVarInsn(Opcodes.ALOAD, 0); - super.visitFieldInsn( - Opcodes.GETFIELD, - "appeng/core/sync/packets/PacketCompressedNBT", - "in", - "Lnet/minecraft/nbt/NBTTagCompound;"); - super.visitMethodInsn( - Opcodes.INVOKESTATIC, - "com/glodblock/github/coremod/hooker/CoreModHooksClient", - "clientPacketData", - "(Lnet/minecraft/nbt/NBTTagCompound;)V", - false); - super.visitInsn(opcode); - } - } -} diff --git a/src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java b/src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java index e40085228..63fb6d40f 100644 --- a/src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/crossmod/opencomputers/DriverLevelMaintainer.java @@ -83,7 +83,7 @@ private boolean setEnable(Arguments args) { throw new IllegalArgumentException("Invalid slot"); } boolean enable = args.checkBoolean(1); - tileEntity.requests.setEnable(slot, enable); + tileEntity.requests.updateStatus(slot, enable); return true; } } diff --git a/src/main/java/com/glodblock/github/crossmod/waila/TileWailaDataProvider.java b/src/main/java/com/glodblock/github/crossmod/waila/TileWailaDataProvider.java index 47fdabc70..4790ab0d1 100644 --- a/src/main/java/com/glodblock/github/crossmod/waila/TileWailaDataProvider.java +++ b/src/main/java/com/glodblock/github/crossmod/waila/TileWailaDataProvider.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; import com.glodblock.github.crossmod.waila.tile.FluidInvWailaDataProvider; -import com.glodblock.github.crossmod.waila.tile.LevelMaintainerWailaDataProvide; +import com.glodblock.github.crossmod.waila.tile.LevelMaintainerWailaDataProvider; import com.google.common.collect.Lists; import mcp.mobius.waila.api.IWailaConfigHandler; @@ -22,7 +22,7 @@ public class TileWailaDataProvider implements IWailaDataProvider { public TileWailaDataProvider() { final IWailaDataProvider fluidInv = new FluidInvWailaDataProvider(); - final IWailaDataProvider levelMaintainer = new LevelMaintainerWailaDataProvide(); + final IWailaDataProvider levelMaintainer = new LevelMaintainerWailaDataProvider(); this.providers = Lists.newArrayList(fluidInv, levelMaintainer); } diff --git a/src/main/java/com/glodblock/github/crossmod/waila/tile/LevelMaintainerWailaDataProvide.java b/src/main/java/com/glodblock/github/crossmod/waila/tile/LevelMaintainerWailaDataProvider.java similarity index 76% rename from src/main/java/com/glodblock/github/crossmod/waila/tile/LevelMaintainerWailaDataProvide.java rename to src/main/java/com/glodblock/github/crossmod/waila/tile/LevelMaintainerWailaDataProvider.java index 76f055817..7cc01b0d0 100644 --- a/src/main/java/com/glodblock/github/crossmod/waila/tile/LevelMaintainerWailaDataProvide.java +++ b/src/main/java/com/glodblock/github/crossmod/waila/tile/LevelMaintainerWailaDataProvider.java @@ -16,23 +16,23 @@ import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; -public class LevelMaintainerWailaDataProvide extends BaseWailaDataProvider { +public class LevelMaintainerWailaDataProvider extends BaseWailaDataProvider { @Override public List getWailaBody(final ItemStack itemStack, final List currentToolTip, final IWailaDataAccessor accessor, final IWailaConfigHandler config) { final TileEntity te = accessor.getTileEntity(); - if (te instanceof TileLevelMaintainer) { + if (te instanceof TileLevelMaintainer tileLevelMaintainer) { te.readFromNBT(accessor.getNBTData()); for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { - IAEItemStack ias = ((TileLevelMaintainer) te).requests.getRequestStacks().getStack(i); + IAEItemStack ias = tileLevelMaintainer.requests.getAEItemStack(i); if (ias != null) { currentToolTip.add( Tooltip.tileLevelMaintainerFormat( ias.getItemStack().getDisplayName(), - ((TileLevelMaintainer) te).requests.getQuantity(i), - ((TileLevelMaintainer) te).requests.getBatchSize(i), - ((TileLevelMaintainer) te).requests.isEnable(i))); + tileLevelMaintainer.requests.getQuantity(i), + tileLevelMaintainer.requests.getBatchSize(i), + tileLevelMaintainer.requests.isEnable(i))); } } } diff --git a/src/main/java/com/glodblock/github/inventory/gui/GuiType.java b/src/main/java/com/glodblock/github/inventory/gui/GuiType.java index a89d0f73d..45bd85936 100644 --- a/src/main/java/com/glodblock/github/inventory/gui/GuiType.java +++ b/src/main/java/com/glodblock/github/inventory/gui/GuiType.java @@ -6,6 +6,7 @@ import net.minecraft.entity.player.EntityPlayer; +import com.glodblock.github.client.gui.GuiCraftingStatus; import com.glodblock.github.client.gui.GuiDualInterface; import com.glodblock.github.client.gui.GuiEssentiaTerminal; import com.glodblock.github.client.gui.GuiFCPriority; @@ -20,16 +21,17 @@ import com.glodblock.github.client.gui.GuiFluidPatternEncoder; import com.glodblock.github.client.gui.GuiFluidPatternExWireless; import com.glodblock.github.client.gui.GuiFluidPatternTerminal; -import com.glodblock.github.client.gui.GuiFluidPatternTerminalCraftingStatus; import com.glodblock.github.client.gui.GuiFluidPatternTerminalEx; import com.glodblock.github.client.gui.GuiFluidPatternWireless; import com.glodblock.github.client.gui.GuiFluidPortableCell; import com.glodblock.github.client.gui.GuiFluidStorageBus; import com.glodblock.github.client.gui.GuiFluidTerminal; import com.glodblock.github.client.gui.GuiIngredientBuffer; -import com.glodblock.github.client.gui.GuiInterfaceTerminalWireless; +import com.glodblock.github.client.gui.GuiInterfaceWireless; import com.glodblock.github.client.gui.GuiLargeIngredientBuffer; import com.glodblock.github.client.gui.GuiLevelMaintainer; +import com.glodblock.github.client.gui.GuiLevelTerminal; +import com.glodblock.github.client.gui.GuiLevelWireless; import com.glodblock.github.client.gui.GuiOCPatternEditor; import com.glodblock.github.client.gui.GuiPatternValueAmount; import com.glodblock.github.client.gui.GuiRenamer; @@ -54,6 +56,8 @@ import com.glodblock.github.client.gui.container.ContainerInterfaceWireless; import com.glodblock.github.client.gui.container.ContainerLargeIngredientBuffer; import com.glodblock.github.client.gui.container.ContainerLevelMaintainer; +import com.glodblock.github.client.gui.container.ContainerLevelTerminal; +import com.glodblock.github.client.gui.container.ContainerLevelWireless; import com.glodblock.github.client.gui.container.ContainerOCPatternEditor; import com.glodblock.github.client.gui.container.ContainerPatternValueAmount; import com.glodblock.github.client.gui.container.ContainerRenamer; @@ -246,7 +250,7 @@ protected Object createServerGui(EntityPlayer player, ITerminalHost inv) { @Override protected Object createClientGui(EntityPlayer player, ITerminalHost inv) { - return new GuiFluidPatternTerminalCraftingStatus(player.inventory, inv); + return new GuiCraftingStatus(player.inventory, inv); } }), @@ -263,6 +267,19 @@ protected Object createClientGui(EntityPlayer player, ITerminalHost inv) { } }), + LEVEL_TERMINAL(new TileOrPartGuiFactory<>(ITerminalHost.class) { + + @Override + protected Object createServerGui(EntityPlayer player, ITerminalHost inv) { + return new ContainerLevelTerminal(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, ITerminalHost inv) { + return new GuiLevelTerminal(player.inventory, inv); + } + }), + PORTABLE_FLUID_CELL(new ItemGuiFactory<>(IFluidPortableCell.class) { @Override @@ -335,7 +352,20 @@ protected Object createServerGui(EntityPlayer player, IWirelessTerminal inv) { @Override protected Object createClientGui(EntityPlayer player, IWirelessTerminal inv) { - return new GuiInterfaceTerminalWireless(player.inventory, inv); + return new GuiInterfaceWireless(player.inventory, inv); + } + }), + + WIRELESS_LEVEL_TERMINAL(new ItemGuiFactory<>(IWirelessTerminal.class) { + + @Override + protected Object createServerGui(EntityPlayer player, IWirelessTerminal inv) { + return new ContainerLevelWireless(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, IWirelessTerminal inv) { + return new GuiLevelWireless(player.inventory, inv); } }), diff --git a/src/main/java/com/glodblock/github/inventory/item/IWirelessInterfaceTerminal.java b/src/main/java/com/glodblock/github/inventory/item/IClickableInTerminal.java similarity index 74% rename from src/main/java/com/glodblock/github/inventory/item/IWirelessInterfaceTerminal.java rename to src/main/java/com/glodblock/github/inventory/item/IClickableInTerminal.java index 19118dd0d..280486d5f 100644 --- a/src/main/java/com/glodblock/github/inventory/item/IWirelessInterfaceTerminal.java +++ b/src/main/java/com/glodblock/github/inventory/item/IClickableInTerminal.java @@ -2,7 +2,7 @@ import com.glodblock.github.util.Util; -public interface IWirelessInterfaceTerminal extends IWirelessTerminal { +public interface IClickableInTerminal { void setClickedInterface(Util.DimensionalCoordSide tile); diff --git a/src/main/java/com/glodblock/github/inventory/item/WirelessInterfaceTerminalInventory.java b/src/main/java/com/glodblock/github/inventory/item/WirelessInterfaceTerminalInventory.java index 4ee0a9bab..d3bee52bf 100644 --- a/src/main/java/com/glodblock/github/inventory/item/WirelessInterfaceTerminalInventory.java +++ b/src/main/java/com/glodblock/github/inventory/item/WirelessInterfaceTerminalInventory.java @@ -27,7 +27,7 @@ import appeng.util.ConfigManager; import appeng.util.Platform; -public class WirelessInterfaceTerminalInventory implements IWirelessInterfaceTerminal { +public class WirelessInterfaceTerminalInventory implements IClickableInTerminal, IWirelessTerminal { private final ItemStack target; private final IAEItemPowerStorage ips; @@ -125,9 +125,7 @@ public int getInventorySlot() { } @Override - public void saveChanges() { - - } + public void saveChanges() {} @Override public void onChangeInventory(IInventory inv, int slot, InvOperation mc, ItemStack removedStack, diff --git a/src/main/java/com/glodblock/github/inventory/item/WirelessLevelTerminalInventory.java b/src/main/java/com/glodblock/github/inventory/item/WirelessLevelTerminalInventory.java new file mode 100644 index 000000000..8150d6a1a --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/item/WirelessLevelTerminalInventory.java @@ -0,0 +1,146 @@ +package com.glodblock.github.inventory.item; + +import java.util.Objects; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import com.glodblock.github.util.Util; + +import appeng.api.config.Actionable; +import appeng.api.config.PowerMultiplier; +import appeng.api.config.Settings; +import appeng.api.config.TerminalStyle; +import appeng.api.implementations.items.IAEItemPowerStorage; +import appeng.api.networking.IGridNode; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.AECableType; +import appeng.api.util.IConfigManager; +import appeng.items.tools.powered.ToolWirelessTerminal; +import appeng.tile.inventory.InvOperation; +import appeng.util.ConfigManager; +import appeng.util.Platform; + +public class WirelessLevelTerminalInventory implements IClickableInTerminal, IWirelessTerminal { + + private final ItemStack target; + private final IAEItemPowerStorage ips; + private final int inventorySlot; + private final IGridNode grid; + private Util.DimensionalCoordSide tile; + + public WirelessLevelTerminalInventory(ItemStack is, int slot, IGridNode gridNode, EntityPlayer player) { + Objects.requireNonNull(Util.getWirelessInv(is, player, StorageChannel.ITEMS)); + this.ips = (ToolWirelessTerminal) is.getItem(); + this.grid = gridNode; + this.target = is; + this.inventorySlot = slot; + readFromNBT(); + } + + public void readFromNBT() { + NBTTagCompound data = Platform.openNbtData(this.target); + if (data.hasKey("clickedInterface")) { + NBTTagCompound tileMsg = (NBTTagCompound) data.getTag("clickedInterface"); + this.tile = Util.DimensionalCoordSide.readFromNBT(tileMsg); + } + } + + public void writeToNBT() { + NBTTagCompound data = Platform.openNbtData(this.target); + NBTTagCompound tileMsg = new NBTTagCompound(); + tile.writeToNBT(tileMsg); + data.setTag("clickedInterface", tileMsg); + } + + @Override + public IGridNode getActionableNode() { + return this.grid; + } + + @Override + public IGridNode getGridNode(ForgeDirection dir) { + return this.grid; + } + + @Override + public AECableType getCableConnectionType(ForgeDirection dir) { + return AECableType.NONE; + } + + @Override + public void securityBreak() { + this.getGridNode(ForgeDirection.UNKNOWN).getMachine().securityBreak(); + } + + @Override + public ItemStack getItemStack() { + return this.target; + } + + @Override + public IInventory getViewCellStorage() { + return null; + } + + @Override + public double extractAEPower(double amt, Actionable mode, PowerMultiplier usePowerMultiplier) { + amt = usePowerMultiplier.multiply(amt); + if (mode == Actionable.SIMULATE) { + return usePowerMultiplier.divide(Math.min(amt, this.ips.getAECurrentPower(this.target))); + } + return usePowerMultiplier.divide(this.ips.extractAEPower(this.target, amt)); + } + + @Override + public IMEMonitor getItemInventory() { + return null; + } + + @Override + public IMEMonitor getFluidInventory() { + return null; + } + + @Override + public IConfigManager getConfigManager() { + final ConfigManager out = new ConfigManager((manager, settingName, newValue) -> { + final NBTTagCompound data = Platform.openNbtData(this.target); + manager.writeToNBT(data); + }); + out.registerSetting(Settings.TERMINAL_STYLE, TerminalStyle.SMALL); + out.readFromNBT((NBTTagCompound) Platform.openNbtData(this.target).copy()); + return out; + } + + @Override + public int getInventorySlot() { + return this.inventorySlot; + } + + @Override + public void saveChanges() {} + + @Override + public void onChangeInventory(IInventory inv, int slot, InvOperation mc, ItemStack removedStack, + ItemStack newStack) { + + } + + @Override + public void setClickedInterface(Util.DimensionalCoordSide tile) { + this.tile = tile; + this.writeToNBT(); + } + + @Override + public Util.DimensionalCoordSide getClickedInterface() { + return this.tile; + } +} diff --git a/src/main/java/com/glodblock/github/loader/ChannelLoader.java b/src/main/java/com/glodblock/github/loader/ChannelLoader.java index e1d78dbf4..0312a07a0 100644 --- a/src/main/java/com/glodblock/github/loader/ChannelLoader.java +++ b/src/main/java/com/glodblock/github/loader/ChannelLoader.java @@ -12,16 +12,19 @@ import com.glodblock.github.network.CPacketFluidUpdate; import com.glodblock.github.network.CPacketInventoryAction; import com.glodblock.github.network.CPacketLevelMaintainer; +import com.glodblock.github.network.CPacketLevelTerminalCommands; import com.glodblock.github.network.CPacketPatternValueSet; import com.glodblock.github.network.CPacketRenamer; import com.glodblock.github.network.CPacketSwitchGuis; import com.glodblock.github.network.CPacketTransferRecipe; import com.glodblock.github.network.CPacketValueConfig; import com.glodblock.github.network.SPacketFluidUpdate; +import com.glodblock.github.network.SPacketLevelTerminalUpdate; import com.glodblock.github.network.SPacketMEFluidInvUpdate; import com.glodblock.github.network.SPacketMEItemInvUpdate; import com.glodblock.github.network.SPacketSetItemAmount; import com.glodblock.github.network.SPacketStringUpdate; +import com.glodblock.github.network.wrapper.FCNetworkWrapper; import cpw.mods.fml.relauncher.Side; @@ -30,51 +33,49 @@ public class ChannelLoader implements Runnable { public static final ChannelLoader INSTANCE = new ChannelLoader(); @Override - @SuppressWarnings("all") public void run() { int id = 0; - FluidCraft.proxy.netHandler - .registerMessage(new CPacketSwitchGuis.Handler(), CPacketSwitchGuis.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler.registerMessage( + FCNetworkWrapper netHandler = FluidCraft.proxy.netHandler; + netHandler.registerMessage(new CPacketSwitchGuis.Handler(), CPacketSwitchGuis.class, id++, Side.SERVER); + netHandler.registerMessage( new CPacketFluidPatternTermBtns.Handler(), CPacketFluidPatternTermBtns.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketEncodePattern.Handler(), CPacketEncodePattern.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler + netHandler.registerMessage(new CPacketEncodePattern.Handler(), CPacketEncodePattern.class, id++, Side.SERVER); + netHandler .registerMessage(new SPacketMEItemInvUpdate.Handler(), SPacketMEItemInvUpdate.class, id++, Side.CLIENT); - FluidCraft.proxy.netHandler.registerMessage( + netHandler.registerMessage( new SPacketMEFluidInvUpdate.Handler(), SPacketMEFluidInvUpdate.class, id++, Side.CLIENT); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketCraftRequest.Handler(), CPacketCraftRequest.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler + netHandler.registerMessage(new CPacketCraftRequest.Handler(), CPacketCraftRequest.class, id++, Side.SERVER); + netHandler .registerMessage(new CPacketInventoryAction.Handler(), CPacketInventoryAction.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketSwitchGuis.Handler(), CPacketSwitchGuis.class, id++, Side.CLIENT); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketTransferRecipe.Handler(), CPacketTransferRecipe.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketDumpTank.Handler(), CPacketDumpTank.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new SPacketFluidUpdate.Handler(), SPacketFluidUpdate.class, id++, Side.CLIENT); - FluidCraft.proxy.netHandler + netHandler.registerMessage(new CPacketSwitchGuis.Handler(), CPacketSwitchGuis.class, id++, Side.CLIENT); + netHandler.registerMessage(new CPacketTransferRecipe.Handler(), CPacketTransferRecipe.class, id++, Side.SERVER); + netHandler.registerMessage(new CPacketDumpTank.Handler(), CPacketDumpTank.class, id++, Side.SERVER); + netHandler.registerMessage(new SPacketFluidUpdate.Handler(), SPacketFluidUpdate.class, id++, Side.CLIENT); + netHandler .registerMessage(new CPacketPatternValueSet.Handler(), CPacketPatternValueSet.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketValueConfig.Handler(), CPacketValueConfig.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketFluidUpdate.Handler(), CPacketFluidUpdate.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler + netHandler.registerMessage(new CPacketValueConfig.Handler(), CPacketValueConfig.class, id++, Side.SERVER); + netHandler.registerMessage(new CPacketFluidUpdate.Handler(), CPacketFluidUpdate.class, id++, Side.SERVER); + netHandler .registerMessage(new CPacketLevelMaintainer.Handler(), CPacketLevelMaintainer.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new SPacketSetItemAmount.Handler(), SPacketSetItemAmount.class, id++, Side.CLIENT); - FluidCraft.proxy.netHandler - .registerMessage(new CPacketRenamer.Handler(), CPacketRenamer.class, id++, Side.SERVER); - FluidCraft.proxy.netHandler - .registerMessage(new SPacketStringUpdate.Handler(), SPacketStringUpdate.class, id++, Side.CLIENT); + netHandler.registerMessage(new SPacketSetItemAmount.Handler(), SPacketSetItemAmount.class, id++, Side.CLIENT); + netHandler.registerMessage(new CPacketRenamer.Handler(), CPacketRenamer.class, id++, Side.SERVER); + netHandler.registerMessage(new SPacketStringUpdate.Handler(), SPacketStringUpdate.class, id++, Side.CLIENT); + netHandler.registerMessage( + new SPacketLevelTerminalUpdate.Handler(), + SPacketLevelTerminalUpdate.class, + id++, + Side.CLIENT); + netHandler.registerMessage( + new CPacketLevelTerminalCommands.Handler(), + CPacketLevelTerminalCommands.class, + id++, + Side.SERVER); } public static void sendPacketToAllPlayers(Packet packet, World world) { diff --git a/src/main/java/com/glodblock/github/loader/ItemAndBlockHolder.java b/src/main/java/com/glodblock/github/loader/ItemAndBlockHolder.java index 5b6e2b990..5aa5ab89f 100644 --- a/src/main/java/com/glodblock/github/loader/ItemAndBlockHolder.java +++ b/src/main/java/com/glodblock/github/loader/ItemAndBlockHolder.java @@ -35,9 +35,11 @@ import com.glodblock.github.common.item.ItemPartFluidPatternTerminalEx; import com.glodblock.github.common.item.ItemPartFluidStorageBus; import com.glodblock.github.common.item.ItemPartFluidTerminal; +import com.glodblock.github.common.item.ItemPartLevelTerminal; import com.glodblock.github.common.item.ItemPortableFluidCell; import com.glodblock.github.common.item.ItemWirelessFluidTerminal; import com.glodblock.github.common.item.ItemWirelessInterfaceTerminal; +import com.glodblock.github.common.item.ItemWirelessLevelTerminal; import com.glodblock.github.common.item.ItemWirelessPatternTerminal; import com.glodblock.github.common.item.ItemWirelessUltraTerminal; import com.glodblock.github.common.storage.CellType; @@ -64,6 +66,7 @@ public class ItemAndBlockHolder { public static ItemPartFluidPatternTerminalEx FLUID_TERMINAL_EX = new ItemPartFluidPatternTerminalEx().register(); public static ItemPartFluidInterface FLUID_INTERFACE = new ItemPartFluidInterface().register(); public static ItemPartFluidP2PInterface FLUID_INTERFACE_P2P = new ItemPartFluidP2PInterface().register(); + public static ItemPartLevelTerminal LEVEL_TERMINAL = new ItemPartLevelTerminal().register(); public static ItemFluidImportBus FLUID_IMPORT_BUS = new ItemFluidImportBus().register(); public static ItemFluidExportBus FLUID_EXPORT_BUS = new ItemFluidExportBus().register(); public static ItemPartFluidStorageBus FLUID_STORAGE_BUS = new ItemPartFluidStorageBus().register(); @@ -72,8 +75,9 @@ public class ItemAndBlockHolder { public static ItemFluidConversionMonitor FLUID_CONVERSION_MONITOR = new ItemFluidConversionMonitor().register(); public static ItemPortableFluidCell PORTABLE_FLUID_CELL = new ItemPortableFluidCell().register(); public static ItemWirelessFluidTerminal WIRELESS_FLUID_TERM = new ItemWirelessFluidTerminal().register(); - public static ItemWirelessUltraTerminal WIRELESS_ULTRA_TERM = new ItemWirelessUltraTerminal().register(); + public static ItemWirelessLevelTerminal WIRELESS_LEVEL_TERM = new ItemWirelessLevelTerminal().register(); public static ItemWirelessPatternTerminal WIRELESS_PATTERN_TERM = new ItemWirelessPatternTerminal().register(); + public static ItemWirelessUltraTerminal WIRELESS_ULTRA_TERM = new ItemWirelessUltraTerminal().register(); public static ItemWirelessInterfaceTerminal WIRELESS_INTERFACE_TERM = new ItemWirelessInterfaceTerminal() .register(); public static ItemFluidPacket PACKET = new ItemFluidPacket().register(); diff --git a/src/main/java/com/glodblock/github/loader/RecipeLoader.java b/src/main/java/com/glodblock/github/loader/RecipeLoader.java index b8f3774db..878a3bf85 100644 --- a/src/main/java/com/glodblock/github/loader/RecipeLoader.java +++ b/src/main/java/com/glodblock/github/loader/RecipeLoader.java @@ -1,7 +1,56 @@ package com.glodblock.github.loader; import static com.glodblock.github.common.storage.CellType.Cell16384kPart; -import static com.glodblock.github.loader.ItemAndBlockHolder.*; +import static com.glodblock.github.loader.ItemAndBlockHolder.BUFFER; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL1024K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL1024KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL16384K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL16384KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL16K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL16KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL1K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL1KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL256K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL256KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL4096K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL4096KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL4K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL4KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL64K; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL64KM; +import static com.glodblock.github.loader.ItemAndBlockHolder.CELL_HOUSING; +import static com.glodblock.github.loader.ItemAndBlockHolder.CERTUS_QUARTZ_TANK; +import static com.glodblock.github.loader.ItemAndBlockHolder.DECODER; +import static com.glodblock.github.loader.ItemAndBlockHolder.DISCRETIZER; +import static com.glodblock.github.loader.ItemAndBlockHolder.ENCODER; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_AUTO_FILLER; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_BUFFER; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_CONVERSION_MONITOR; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_EXPORT_BUS; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_IMPORT_BUS; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_INTERFACE; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_INTERFACE_P2P; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_LEVEL_EMITTER; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_STORAGE_BUS; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_STORAGE_MONITOR; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_TERM; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_TERMINAL; +import static com.glodblock.github.loader.ItemAndBlockHolder.FLUID_TERMINAL_EX; +import static com.glodblock.github.loader.ItemAndBlockHolder.INTERFACE; +import static com.glodblock.github.loader.ItemAndBlockHolder.LARGE_BUFFER; +import static com.glodblock.github.loader.ItemAndBlockHolder.LEVEL_MAINTAINER; +import static com.glodblock.github.loader.ItemAndBlockHolder.LEVEL_TERMINAL; +import static com.glodblock.github.loader.ItemAndBlockHolder.OC_EDITOR; +import static com.glodblock.github.loader.ItemAndBlockHolder.PATTERN; +import static com.glodblock.github.loader.ItemAndBlockHolder.PORTABLE_FLUID_CELL; +import static com.glodblock.github.loader.ItemAndBlockHolder.QUANTUM_CELL; +import static com.glodblock.github.loader.ItemAndBlockHolder.SINGULARITY_CELL; +import static com.glodblock.github.loader.ItemAndBlockHolder.WALRUS; +import static com.glodblock.github.loader.ItemAndBlockHolder.WIRELESS_FLUID_TERM; +import static com.glodblock.github.loader.ItemAndBlockHolder.WIRELESS_INTERFACE_TERM; +import static com.glodblock.github.loader.ItemAndBlockHolder.WIRELESS_LEVEL_TERM; +import static com.glodblock.github.loader.ItemAndBlockHolder.WIRELESS_PATTERN_TERM; +import static com.glodblock.github.loader.ItemAndBlockHolder.WIRELESS_ULTRA_TERM; import static net.minecraft.init.Blocks.redstone_torch; import static net.minecraft.init.Items.fish; @@ -156,6 +205,7 @@ public void run() { GameRegistry.addShapelessRecipe(WIRELESS_FLUID_TERM.stack(), AE2_WIRELESS_TERMINAL, BUCKET); GameRegistry.addShapelessRecipe(WIRELESS_PATTERN_TERM.stack(), WIRELESS_FLUID_TERM, FLUID_TERMINAL); GameRegistry.addShapelessRecipe(WIRELESS_INTERFACE_TERM.stack(), AE2_WIRELESS_TERMINAL, AE2_INTERFACE_TERMINAL); + GameRegistry.addShapelessRecipe(WIRELESS_LEVEL_TERM.stack(), AE2_WIRELESS_TERMINAL, LEVEL_MAINTAINER); GameRegistry .addRecipe(new ShapedOreRecipe(CERTUS_QUARTZ_TANK.stack(), "GGG", "G G", "GGG", 'G', AE2_QUARTZ_GLASS)); GameRegistry.addShapelessRecipe(FLUID_AUTO_FILLER.stack(), FLUID_TERMINAL, ENCODER); @@ -276,6 +326,7 @@ public void run() { AE2_PROCESS_ENG)); GameRegistry.addShapelessRecipe(AE2_BLANK_PATTERN, PATTERN.stack()); GameRegistry.addShapelessRecipe(FLUID_TERM.stack(), AE2_TERMINAL, BUFFER); + GameRegistry.addShapelessRecipe(LEVEL_TERMINAL.stack(), AE2_TERMINAL, LEVEL_MAINTAINER); GameRegistry.addShapelessRecipe( FLUID_BUFFER.stack(), LARGE_BUFFER.stack(), @@ -594,10 +645,11 @@ public static void runTerminalRecipe() { GameRegistry.addRecipe(new WirelessTerminalRecipe(WIRELESS_FLUID_TERM.stack())); GameRegistry.addRecipe(new WirelessTerminalRecipe(WIRELESS_ULTRA_TERM.stack())); GameRegistry.addRecipe(new WirelessTerminalRecipe(WIRELESS_INTERFACE_TERM.stack())); + GameRegistry.addRecipe(new WirelessTerminalRecipe(WIRELESS_LEVEL_TERM.stack())); } ItemStack[] term = { AE2_WIRELESS_TERMINAL, WIRELESS_FLUID_TERM.stack(), WIRELESS_PATTERN_TERM.stack(), - WIRELESS_INTERFACE_TERM.stack(), THE_WIRELESS_TERM, WCT_WIRELESS_TERM }; + WIRELESS_INTERFACE_TERM.stack(), WIRELESS_LEVEL_TERM.stack(), THE_WIRELESS_TERM, WCT_WIRELESS_TERM }; GameRegistry.addShapelessRecipe( WIRELESS_ULTRA_TERM.stack(), Arrays.stream(term).filter(Objects::nonNull).toArray()); diff --git a/src/main/java/com/glodblock/github/nei/NEIGuiHandler.java b/src/main/java/com/glodblock/github/nei/AE2FC_NEIGuiHandler.java similarity index 53% rename from src/main/java/com/glodblock/github/nei/NEIGuiHandler.java rename to src/main/java/com/glodblock/github/nei/AE2FC_NEIGuiHandler.java index e2c876203..0aaa48e4b 100644 --- a/src/main/java/com/glodblock/github/nei/NEIGuiHandler.java +++ b/src/main/java/com/glodblock/github/nei/AE2FC_NEIGuiHandler.java @@ -1,13 +1,15 @@ package com.glodblock.github.nei; import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.item.ItemStack; import com.glodblock.github.client.gui.GuiFluidMonitor; import com.glodblock.github.client.gui.GuiItemMonitor; +import com.glodblock.github.client.gui.GuiLevelMaintainer; import codechicken.nei.api.INEIGuiAdapter; -public class NEIGuiHandler extends INEIGuiAdapter { +public class AE2FC_NEIGuiHandler extends INEIGuiAdapter { @Override public boolean hideItemPanelSlot(GuiContainer gui, int x, int y, int w, int h) { @@ -18,4 +20,12 @@ public boolean hideItemPanelSlot(GuiContainer gui, int x, int y, int w, int h) { } return false; } + + @Override + public boolean handleDragNDrop(GuiContainer gui, int mouseX, int mouseY, ItemStack draggedStack, int button) { + if (gui instanceof GuiLevelMaintainer guiLevelMaintainer) { + return guiLevelMaintainer.handleDragNDrop(gui, mouseX, mouseY, draggedStack, button); + } + return super.handleDragNDrop(gui, mouseX, mouseY, draggedStack, button); + } } diff --git a/src/main/java/com/glodblock/github/nei/NEI_FC_Config.java b/src/main/java/com/glodblock/github/nei/NEI_FC_Config.java index 7779686a6..3f08bc67f 100644 --- a/src/main/java/com/glodblock/github/nei/NEI_FC_Config.java +++ b/src/main/java/com/glodblock/github/nei/NEI_FC_Config.java @@ -17,7 +17,7 @@ public class NEI_FC_Config implements IConfigureNEI { @Override public void loadConfig() { - API.registerNEIGuiHandler(new NEIGuiHandler()); + API.registerNEIGuiHandler(new AE2FC_NEIGuiHandler()); API.addSearchProvider(new NEIItemFilter()); API.registerStackStringifyHandler(new FCStackStringifyHandler()); diff --git a/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java b/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java index 2957afd57..d79134f9a 100644 --- a/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java @@ -6,14 +6,11 @@ import javax.annotation.Nullable; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; import com.glodblock.github.client.gui.container.ContainerLevelMaintainer; import com.glodblock.github.common.tile.TileLevelMaintainer; import appeng.api.storage.data.IAEItemStack; -import appeng.util.item.AEItemStack; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; import cpw.mods.fml.common.network.simpleimpl.MessageContext; @@ -21,111 +18,101 @@ public class CPacketLevelMaintainer implements IMessage { - private String action; + public enum Action { + Refresh, + Quantity, + Batch, + Enable, + Disable + } + + private Action action; private long size; private int slotIndex; - public CPacketLevelMaintainer() {} + public CPacketLevelMaintainer() { + this.action = Action.Refresh; + this.slotIndex = 0; + this.size = 0; + } - public CPacketLevelMaintainer(String action, int slotIndex) { + public CPacketLevelMaintainer(Action action) { this.action = action; + this.slotIndex = 0; this.size = 0; - this.slotIndex = slotIndex; } - public CPacketLevelMaintainer(String action) { + public CPacketLevelMaintainer(Action action, int slotIndex) { this.action = action; + this.slotIndex = slotIndex; this.size = 0; - this.slotIndex = 0; } - public CPacketLevelMaintainer(String action, int slotIndex, long size) { + public CPacketLevelMaintainer(Action action, int slotIndex, long size) { this.action = action; - this.size = size; this.slotIndex = slotIndex; + this.size = size; } - public CPacketLevelMaintainer(String action, int slotIndex, String size) { + public CPacketLevelMaintainer(Action action, int slotIndex, String size) { this.action = action; this.slotIndex = slotIndex; this.size = size.isEmpty() ? 0 : Long.parseLong(size); } - public static IAEItemStack setTag(IAEItemStack ias, long batch, int slotIndex, boolean enable, int state) { - NBTTagCompound data = new NBTTagCompound(); - ItemStack is = ias.getItemStack(); - data.setLong("Batch", batch); - data.setLong("Index", slotIndex); - data.setBoolean("Enable", enable); - data.setInteger("State", state); - is.setTagCompound(data); - IAEItemStack iaeItemStack = AEItemStack.create(is); - iaeItemStack.setStackSize(ias.getStackSize()); - return iaeItemStack; - } - @Override public void fromBytes(ByteBuf buf) { - int leAction = buf.readInt(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < leAction; i++) { - sb.append(buf.readChar()); - } - this.action = sb.toString(); + this.action = Action.values()[buf.readInt()]; this.slotIndex = buf.readInt(); this.size = buf.readLong(); } @Override public void toBytes(ByteBuf buf) { - buf.writeInt(this.action.length()); - for (int i = 0; i < this.action.length(); i++) { - buf.writeChar(this.action.charAt(i)); - } + buf.writeInt(this.action.ordinal()); buf.writeInt(this.slotIndex); buf.writeLong(this.size); } public static class Handler implements IMessageHandler { - private void refresh(ContainerLevelMaintainer cca, EntityPlayerMP player) { + private List refresh(ContainerLevelMaintainer cca) { List toSend = new ArrayList<>(TileLevelMaintainer.REQ_COUNT); for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { - IAEItemStack is = cca.getTile().requests.getRequestQtyStack(i); - IAEItemStack is1 = cca.getTile().requests.getRequestBatches().getStack(i); - if (is != null) { - if (is1 != null) { - NBTTagCompound data; - data = is1.getItemStack().getTagCompound(); - toSend.add( - setTag( - is, - is1.getStackSize(), - i, - data.getBoolean("Enable"), - cca.getTile().requests.getState(i).ordinal())); - } else { - toSend.add(setTag(is, 0, i, true, 0)); - } + IAEItemStack ias = cca.getTile().requests.getAEItemStack(i); + if (ias != null) { + toSend.add(ias); } } - SPacketMEUpdateBuffer.scheduleItemUpdate(player, toSend); + return toSend; } @Nullable @Override public IMessage onMessage(CPacketLevelMaintainer message, MessageContext ctx) { - if (message.action.startsWith("TileLevelMaintainer.") - && ctx.getServerHandler().playerEntity.openContainer instanceof final ContainerLevelMaintainer cca) { + if (ctx.getServerHandler().playerEntity.openContainer instanceof final ContainerLevelMaintainer clm) { EntityPlayerMP player = ctx.getServerHandler().playerEntity; - switch (message.action) { - case "TileLevelMaintainer.Quantity" -> cca.getTile() - .updateQuantity(message.slotIndex, message.size); - case "TileLevelMaintainer.Batch" -> cca.getTile().updateBatchSize(message.slotIndex, message.size); - case "TileLevelMaintainer.Enable" -> cca.getTile().setRequestStatus(message.slotIndex, false); - case "TileLevelMaintainer.Disable" -> cca.getTile().setRequestStatus(message.slotIndex, true); - } - this.refresh(cca, player); + List toSend = switch (message.action) { + case Quantity -> { + clm.getTile().updateQuantity(message.slotIndex, message.size); + yield this.refresh(clm); + } + case Batch -> { + clm.getTile().updateBatchSize(message.slotIndex, message.size); + yield this.refresh(clm); + } + case Enable -> { + clm.getTile().updateStatus(message.slotIndex, false); + yield this.refresh(clm); + } + case Disable -> { + clm.getTile().updateStatus(message.slotIndex, true); + yield this.refresh(clm); + } + case Refresh -> this.refresh(clm); + }; + + SPacketMEUpdateBuffer.scheduleItemUpdate(player, toSend); } return null; } diff --git a/src/main/java/com/glodblock/github/network/CPacketLevelTerminalCommands.java b/src/main/java/com/glodblock/github/network/CPacketLevelTerminalCommands.java new file mode 100644 index 000000000..a07c706b1 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketLevelTerminalCommands.java @@ -0,0 +1,155 @@ +package com.glodblock.github.network; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.util.ForgeDirection; + +import com.glodblock.github.client.gui.GuiLevelMaintainer; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.inventory.gui.GuiType; +import com.glodblock.github.inventory.item.IClickableInTerminal; +import com.glodblock.github.util.BlockPos; +import com.glodblock.github.util.Util; + +import appeng.container.AEBaseContainer; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; + +public class CPacketLevelTerminalCommands implements IMessage { + + private Action action; + private int x; + private int y; + private int z; + private int dim; + private ForgeDirection side; + + public enum Action { + EDIT, + BACK, + ENABLE, + DISABLE, + ENABLE_ALL, + DISABLE_ALL, + } + + public CPacketLevelTerminalCommands() {} + + public CPacketLevelTerminalCommands(Action action, int x, int y, int z, int dim, ForgeDirection side) { + this.action = action; + this.x = x; + this.y = y; + this.z = z; + this.dim = dim; + this.side = side; + } + + @Override + public void fromBytes(ByteBuf buf) { + action = Action.values()[buf.readInt()]; + switch (action) { + case EDIT, BACK -> { + x = buf.readInt(); + y = buf.readInt(); + z = buf.readInt(); + dim = buf.readInt(); + side = ForgeDirection.getOrientation(buf.readInt()); + } + case ENABLE -> {} + case DISABLE -> {} + case ENABLE_ALL -> {} + case DISABLE_ALL -> {} + } + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(action.ordinal()); + switch (action) { + case EDIT, BACK -> { + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeInt(dim); + buf.writeInt(side.ordinal()); + } + case ENABLE -> {} + case DISABLE -> {} + case ENABLE_ALL -> {} + case DISABLE_ALL -> {} + } + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(CPacketLevelTerminalCommands message, MessageContext ctx) { + EntityPlayerMP player = ctx.getServerHandler().playerEntity; + AEBaseContainer con = (AEBaseContainer) player.openContainer; + switch (message.action) { + case EDIT -> { + TileEntity tile = DimensionManager.getWorld(message.dim) + .getTileEntity(message.x, message.y, message.z); + InventoryHandler.openGui( + player, + player.worldObj, + new BlockPos(tile), + message.side, + GuiType.LEVEL_MAINTAINER); + } + case BACK -> { + GuiType originalGui = null; + final GuiScreen gs = Minecraft.getMinecraft().currentScreen; + if (gs instanceof GuiLevelMaintainer guiLevelMaintainer) { + originalGui = guiLevelMaintainer.getOriginalGui(); + } + if (originalGui == null) { + return null; + } + + InventoryHandler.openGui( + player, + player.worldObj, + new BlockPos(message.x, message.y, message.z, DimensionManager.getWorld(message.dim)), + message.side, + originalGui); + } + case ENABLE -> { + if (con.getTarget() instanceof IClickableInTerminal clickableInterface) { + Util.DimensionalCoordSide intMsg = clickableInterface.getClickedInterface(); + TileEntity tile = DimensionManager.getWorld(intMsg.getDimension()) + .getTileEntity(intMsg.x, intMsg.y, intMsg.z); + } + } + case DISABLE -> { + if (con.getTarget() instanceof IClickableInTerminal clickableInterface) { + Util.DimensionalCoordSide intMsg = clickableInterface.getClickedInterface(); + TileEntity tile = DimensionManager.getWorld(intMsg.getDimension()) + .getTileEntity(intMsg.x, intMsg.y, intMsg.z); + } + } + case ENABLE_ALL -> { + if (con.getTarget() instanceof IClickableInTerminal clickableInterface) { + Util.DimensionalCoordSide intMsg = clickableInterface.getClickedInterface(); + TileEntity tile = DimensionManager.getWorld(intMsg.getDimension()) + .getTileEntity(intMsg.x, intMsg.y, intMsg.z); + } + } + case DISABLE_ALL -> { + if (con.getTarget() instanceof IClickableInTerminal clickableInterface) { + Util.DimensionalCoordSide intMsg = clickableInterface.getClickedInterface(); + TileEntity tile = DimensionManager.getWorld(intMsg.getDimension()) + .getTileEntity(intMsg.x, intMsg.y, intMsg.z); + } + } + } + return null; + } + + } +} diff --git a/src/main/java/com/glodblock/github/network/CPacketRenamer.java b/src/main/java/com/glodblock/github/network/CPacketRenamer.java index 46450a49d..601b03837 100644 --- a/src/main/java/com/glodblock/github/network/CPacketRenamer.java +++ b/src/main/java/com/glodblock/github/network/CPacketRenamer.java @@ -1,19 +1,22 @@ package com.glodblock.github.network; -import static com.glodblock.github.common.item.ItemWirelessUltraTerminal.getGuis; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.util.ForgeDirection; import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.gui.GuiRenamer; import com.glodblock.github.inventory.InventoryHandler; import com.glodblock.github.inventory.gui.GuiType; -import com.glodblock.github.inventory.item.IWirelessInterfaceTerminal; +import com.glodblock.github.inventory.item.IClickableInTerminal; +import com.glodblock.github.inventory.item.IWirelessTerminal; import com.glodblock.github.util.BlockPos; import com.glodblock.github.util.Util; +import appeng.api.implementations.IUpgradeableHost; import appeng.container.AEBaseContainer; import appeng.helpers.ICustomNameObject; import appeng.tile.networking.TileCableBus; @@ -121,58 +124,70 @@ private void setName(TileEntity tile, ForgeDirection side, String text) { public IMessage onMessage(CPacketRenamer message, MessageContext ctx) { EntityPlayerMP player = ctx.getServerHandler().playerEntity; AEBaseContainer con = (AEBaseContainer) player.openContainer; - TileEntity tile; - if (message.action == Action.OPEN) { - tile = DimensionManager.getWorld(message.dim).getTileEntity(message.x, message.y, message.z); - if (tile != null && con.getTarget() instanceof IWirelessInterfaceTerminal - && tile instanceof ICustomNameObject) { - String name = getName(tile, message.side); - ((IWirelessInterfaceTerminal) con.getTarget()).setClickedInterface( - new Util.DimensionalCoordSide( - message.x, - message.y, - message.z, - message.dim, + switch (message.action) { + case OPEN -> { + if (con.getTarget() instanceof IClickableInTerminal clickableInterface) { + TileEntity tile = DimensionManager.getWorld(message.dim) + .getTileEntity(message.x, message.y, message.z); + if (!(tile instanceof ICustomNameObject)) { + break; + } + + String name = getName(tile, message.side); + clickableInterface.setClickedInterface( + new Util.DimensionalCoordSide( + message.x, + message.y, + message.z, + message.dim, + message.side, + name)); + + if (con.getTarget() instanceof IWirelessTerminal terminal) { + InventoryHandler.openGui( + player, + player.worldObj, + new BlockPos( + terminal.getInventorySlot(), + Util.GuiHelper.encodeType(0, Util.GuiHelper.GuiType.ITEM), + 1), message.side, - name)); - InventoryHandler.openGui( - player, - player.worldObj, - new BlockPos( - ((IWirelessInterfaceTerminal) con.getTarget()).getInventorySlot(), - Util.GuiHelper.encodeType(0, Util.GuiHelper.GuiType.ITEM), - 1), - message.side, - GuiType.RENAMER); + GuiType.RENAMER); + } else if (con.getTarget() instanceof IUpgradeableHost host) { + InventoryHandler.openGui( + player, + player.worldObj, + new BlockPos(host.getTile()), + con.getOpenContext().getSide(), + GuiType.RENAMER); + } + } } - } else { - if (con.getTarget() instanceof IWirelessInterfaceTerminal) { - Util.DimensionalCoordSide intMsg = ((IWirelessInterfaceTerminal) con.getTarget()) - .getClickedInterface(); - tile = DimensionManager.getWorld(intMsg.getDimension()).getTileEntity(intMsg.x, intMsg.y, intMsg.z); - if (message.action == Action.GET_TEXT) { + case GET_TEXT -> { + if (con.getTarget() instanceof IClickableInTerminal clickableInterface) { + Util.DimensionalCoordSide intMsg = clickableInterface.getClickedInterface(); + TileEntity tile = DimensionManager.getWorld(intMsg.getDimension()) + .getTileEntity(intMsg.x, intMsg.y, intMsg.z); FluidCraft.proxy.netHandler .sendTo(new SPacketStringUpdate(this.getName(tile, intMsg.getSide())), player); - } else { + } + } + case SET_TEXT -> { + if (con.getTarget() instanceof IClickableInTerminal clickableInterface) { + Util.DimensionalCoordSide intMsg = clickableInterface.getClickedInterface(); + TileEntity tile = DimensionManager.getWorld(intMsg.getDimension()) + .getTileEntity(intMsg.x, intMsg.y, intMsg.z); this.setName(tile, intMsg.getSide(), message.text); - InventoryHandler.openGui( - player, - player.worldObj, - new BlockPos( - ((IWirelessInterfaceTerminal) con.getTarget()).getInventorySlot(), - Util.GuiHelper.encodeType( - getGuis().indexOf( - GuiType.valueOf( - GuiType.WIRELESS_INTERFACE_TERMINAL.toString())), - Util.GuiHelper.GuiType.ITEM), - 0), - ForgeDirection.UNKNOWN, - GuiType.WIRELESS_INTERFACE_TERMINAL); + + final GuiScreen gs = Minecraft.getMinecraft().currentScreen; + if (gs instanceof GuiRenamer guiRenamer) { + guiRenamer.switchGui(); + } } } } - return null; } + } } diff --git a/src/main/java/com/glodblock/github/network/SPacketLevelTerminalUpdate.java b/src/main/java/com/glodblock/github/network/SPacketLevelTerminalUpdate.java new file mode 100644 index 000000000..515278f38 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/SPacketLevelTerminalUpdate.java @@ -0,0 +1,585 @@ +package com.glodblock.github.network; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.common.util.ForgeDirection; + +import com.glodblock.github.client.gui.GuiLevelTerminal; + +import appeng.core.AEConfig; +import appeng.core.AELog; +import appeng.core.features.AEFeature; +import cpw.mods.fml.common.network.ByteBufUtils; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.Unpooled; + +/** + * Packet used for level terminal updates. Packet allows the server to send an array of command packets, which are then + * processed in order. This allows for chaining commands to produce the desired update. + */ +public class SPacketLevelTerminalUpdate implements IMessage { + + public static final int CLEAR_ALL_BIT = 1; + public static final int DISCONNECT_BIT = 2; + + private final List commands = new ArrayList<>(); + private int statusFlags; + + public SPacketLevelTerminalUpdate() {} + + public void fromBytes(ByteBuf buf) { + this.statusFlags = buf.readByte(); + int numEntries = buf.readInt(); + + for (int i = 0; i < numEntries; ++i) { + try { + PacketType type = PacketType.values()[buf.readByte()]; + + switch (type) { + case ADD -> this.commands.add(new PacketAdd(buf)); + case REMOVE -> this.commands.add(new PacketRemove(buf)); + case OVERWRITE -> this.commands.add(new PacketOverwrite(buf)); + case RENAME -> this.commands.add(new PacketRename(buf)); + default -> throw new IOException("Unknown packet type received of index " + type); + } + } catch (Exception e) { + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info( + "Corrupted packet commands: (" + i + + ") of (" + + numEntries + + ") -> " + + this.commands.size() + + " : " + + this.commands.stream().map(packetEntry -> packetEntry.getClass().getSimpleName()) + .collect(Collectors.groupingBy(String::new, Collectors.counting()))); + if (AEConfig.instance.isFeatureEnabled(AEFeature.DebugLogging)) { + AELog.info(" <- Parsed content: " + this.commands); + } + } + AELog.debug(e); + return; + } + } + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info( + " <- Received commands " + this.commands.size() + + " : " + + this.commands.stream().map(packetEntry -> packetEntry.getClass().getSimpleName()) + .collect(Collectors.groupingBy(String::new, Collectors.counting()))); + } + } + + public void toBytes(ByteBuf buf) { + try { + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info( + " <- Sent commands " + this.commands.size() + + " : " + + this.commands.stream().map(packetEntry -> packetEntry.getClass().getSimpleName()) + .collect(Collectors.groupingBy(String::new, Collectors.counting()))); + if (AEConfig.instance.isFeatureEnabled(AEFeature.DebugLogging)) { + AELog.info(" -> Sent commands: " + this.commands); + } + } + + buf.writeByte(statusFlags); + buf.writeInt(commands.size()); + for (PacketEntry entry : commands) { + entry.write(buf); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + /** + * Remove all entries on the terminal. This is done BEFORE any entries are processed, so you can set this to clear + * old entries, and add new ones after in one packet. + */ + public void setClear() { + statusFlags |= CLEAR_ALL_BIT; + } + + /** + * The terminal disconnected. Entries are still processed, but indicates for the GUI to darken/turn off the + * terminal. No further updates will arrive until the terminal reconnects. + */ + public void setDisconnect() { + this.statusFlags |= DISCONNECT_BIT; + } + + /** + * Adds a new entry. Fill out the rest of the command using the {@link PacketAdd#setItems(int, int, NBTTagList)} and + * {@link PacketAdd#setLocation(int, int, int, int, int)}. + * + * @return the packet, which needs to have information filled out. + */ + public PacketAdd addNewEntry(long id, String name, boolean online) { + PacketAdd packet = new PacketAdd(id, name, online); + + commands.add(packet); + return packet; + } + + /** + * Remove the entry with the id from the terminal. + */ + public void addRemovalEntry(long id) { + commands.add(new PacketRemove(id)); + } + + /** + * Rename the entry + */ + public void addRenamedEntry(long id, String newName) { + commands.add(new PacketRename(id, newName)); + } + + /** + * Overwrite the entry with new items or new status + */ + public PacketOverwrite addOverwriteEntry(long id) { + PacketOverwrite packet = new PacketOverwrite(id); + + commands.add(packet); + return packet; + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(SPacketLevelTerminalUpdate message, MessageContext ctx) { + final GuiScreen gs = Minecraft.getMinecraft().currentScreen; + + if (gs instanceof GuiLevelTerminal levelTerminal) { + levelTerminal.postUpdate(message.commands, message.statusFlags); + } + + return null; + } + } + + enum PacketType { + ADD, + REMOVE, + OVERWRITE, + RENAME, + } + + /** + * A packet for updating an entry. + */ + public abstract static class PacketEntry { + + public final long entryId; + + protected PacketEntry(long entryId) { + this.entryId = entryId; + } + + protected PacketEntry(ByteBuf buf) throws IOException { + this.entryId = buf.readLong(); + read(buf); + } + + /** + * Needs to write the packet id. + */ + protected abstract void write(ByteBuf buf) throws IOException; + + /** + * Reading the entry id is not needed. + */ + protected abstract void read(ByteBuf buf) throws IOException; + } + + /** + * A command for sending a new entry. + */ + public static class PacketAdd extends PacketEntry { + + public String name; + public int x, y, z, dim, side; + public int rows, rowSize; + public boolean online; + public ItemStack selfItemStack; + public ItemStack displayItemStack; + public NBTTagList items; + + PacketAdd(long id, String name, boolean online) { + super(id); + this.name = name; + this.online = online; + } + + PacketAdd(ByteBuf buf) throws IOException { + super(buf); + } + + public PacketAdd setLocation(int x, int y, int z, int dim, int side) { + this.x = x; + this.y = y; + this.z = z; + this.dim = dim; + this.side = side; + return this; + } + + public PacketAdd setItems(int rows, int rowSize, NBTTagList items) { + this.rows = rows; + this.rowSize = rowSize; + this.items = items; + + return this; + } + + public PacketAdd setViewItemStack(ItemStack selfItemStack, ItemStack displayItemStack) { + this.selfItemStack = selfItemStack; + this.displayItemStack = displayItemStack; + + return this; + } + + @Override + protected void write(ByteBuf buf) throws IOException { + buf.writeByte(PacketType.ADD.ordinal()); + buf.writeLong(entryId); + ByteBufUtils.writeUTF8String(buf, this.name); + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeInt(dim); + buf.writeByte(side); + buf.writeInt(rows); + buf.writeInt(rowSize); + + ByteBuf tempBuf = Unpooled.directBuffer(256); + try { + try (ByteBufOutputStream stream = new ByteBufOutputStream(tempBuf)) { + + NBTTagCompound wrapper = new NBTTagCompound(); + + if (selfItemStack != null) { + wrapper.setTag("self", selfItemStack.writeToNBT(new NBTTagCompound())); + } + if (displayItemStack != null) { + wrapper.setTag("display", displayItemStack.writeToNBT(new NBTTagCompound())); + } + wrapper.setTag("data", items); + CompressedStreamTools.writeCompressed(wrapper, stream); + } + buf.writeInt(tempBuf.readableBytes()); + buf.writeBytes(tempBuf); + } finally { + tempBuf.release(); + } + } + + @Override + protected void read(ByteBuf buf) throws IOException { + this.name = ByteBufUtils.readUTF8String(buf); + this.x = buf.readInt(); + this.y = buf.readInt(); + this.z = buf.readInt(); + this.dim = buf.readInt(); + this.side = buf.readByte(); + this.rows = buf.readInt(); + this.rowSize = buf.readInt(); + int payloadSize = buf.readInt(); + try (ByteBufInputStream stream = new ByteBufInputStream(buf, payloadSize)) { + NBTTagCompound payload = CompressedStreamTools.readCompressed(stream); + int available = stream.available(); + if (available > 0) { + byte[] left = new byte[available]; + int read = stream.read(left); + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info( + "Unread bytes detected (" + read + + "): " + + Arrays.toString(left) + + " at " + + dim + + "#(" + + x + + ":" + + y + + ":" + + z + + ")@" + + ForgeDirection.getOrientation(side)); + } + } + + if (payload.hasKey("self", NBT.TAG_COMPOUND)) { + this.selfItemStack = ItemStack.loadItemStackFromNBT(payload.getCompoundTag("self")); + } + + if (payload.hasKey("display", NBT.TAG_COMPOUND)) { + this.displayItemStack = ItemStack.loadItemStackFromNBT(payload.getCompoundTag("display")); + } + + this.items = payload.getTagList("data", NBT.TAG_COMPOUND); + } + } + + @Override + public String toString() { + return "PacketAdd{" + "name='" + + name + + '\'' + + ", x=" + + x + + ", y=" + + y + + ", z=" + + z + + ", dim=" + + dim + + ", side=" + + side + + ", rows=" + + rows + + ", rowSize=" + + rowSize + + ", online=" + + online + + ", selfItemStack=" + + selfItemStack + + ", displayItemStack=" + + displayItemStack + + ", items=" + + items + + ", entryId=" + + entryId + + '}'; + } + } + + public static class PacketRemove extends PacketEntry { + + PacketRemove(long id) { + super(id); + } + + PacketRemove(ByteBuf buf) throws IOException { + super(buf); + } + + @Override + protected void write(ByteBuf buf) { + buf.writeByte(PacketType.REMOVE.ordinal()); + buf.writeLong(entryId); + } + + @Override + protected void read(ByteBuf buf) {} + + @Override + public String toString() { + return "PacketRemove{" + "entryId=" + entryId + '}'; + } + } + + /** + * Overwrite online status or inventory of the entry. + */ + public static class PacketOverwrite extends PacketEntry { + + public static final int ONLINE_BIT = 1; + public static final int ONLINE_VALID = 1 << 1; + public static final int ITEMS_VALID = 1 << 2; + public static final int ALL_ITEM_UPDATE_BIT = 1 << 3; + public boolean onlineValid; + public boolean online; + public boolean itemsValid; + public boolean allItemUpdate; + public int[] validIndices; + public NBTTagList items; + + protected PacketOverwrite(long id) { + super(id); + } + + protected PacketOverwrite(ByteBuf buf) throws IOException { + super(buf); + } + + public PacketOverwrite setOnline(boolean online) { + this.onlineValid = true; + this.online = online; + return this; + } + + public PacketOverwrite setItems(int[] validIndices, NBTTagList items) { + this.itemsValid = true; + this.allItemUpdate = validIndices == null || validIndices.length == 0; + this.validIndices = validIndices; + this.items = items; + + return this; + } + + public PacketOverwrite setItems(int newSize, NBTTagList items) { + this.itemsValid = true; + this.allItemUpdate = true; + this.validIndices = new int[newSize]; + this.items = items; + + return this; + } + + @Override + protected void write(ByteBuf buf) throws IOException { + buf.writeByte(PacketType.OVERWRITE.ordinal()); + buf.writeLong(entryId); + + int flags = 0; + + if (onlineValid) { + flags |= ONLINE_VALID; + flags |= online ? ONLINE_BIT : 0; + } + if (itemsValid) { + flags |= ITEMS_VALID; + if (allItemUpdate) { + flags |= ALL_ITEM_UPDATE_BIT; + buf.writeByte(flags); + buf.writeInt(validIndices.length); + } else { + buf.writeByte(flags); + buf.writeInt(validIndices.length); + for (int validIndex : validIndices) { + buf.writeInt(validIndex); + } + } + ByteBuf tempBuf = Unpooled.directBuffer(256); + try { + try (ByteBufOutputStream stream = new ByteBufOutputStream(tempBuf)) { + + NBTTagCompound wrapper = new NBTTagCompound(); + + wrapper.setTag("data", items); + CompressedStreamTools.writeCompressed(wrapper, stream); + } + buf.writeInt(tempBuf.readableBytes()); + buf.writeBytes(tempBuf); + } finally { + tempBuf.release(); + } + } else { + buf.writeByte(flags); + } + } + + @Override + protected void read(ByteBuf buf) throws IOException { + int flags = buf.readByte(); + + /* Decide whether to use online flag or not */ + if ((flags & ONLINE_VALID) == ONLINE_VALID) { + this.onlineValid = true; + this.online = (flags & ONLINE_BIT) == ONLINE_BIT; + } + /* Decide whether to read item list or not */ + if ((flags & ITEMS_VALID) == ITEMS_VALID) { + this.itemsValid = true; + if ((flags & ALL_ITEM_UPDATE_BIT) == ALL_ITEM_UPDATE_BIT) { + this.allItemUpdate = true; + int numItems = buf.readInt(); + this.validIndices = new int[numItems]; + } else { + int numItems = buf.readInt(); + this.validIndices = new int[numItems]; + for (int i = 0; i < numItems; ++i) { + this.validIndices[i] = buf.readInt(); + } + } + int payloadSize = buf.readInt(); + try (ByteBufInputStream stream = new ByteBufInputStream(buf, payloadSize)) { + this.items = CompressedStreamTools.readCompressed(stream).getTagList("data", NBT.TAG_COMPOUND); + int available = stream.available(); + if (available > 0) { + byte[] left = new byte[available]; + int read = stream.read(left); + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info("Unread bytes detected (" + read + "): " + Arrays.toString(left)); + } + } + } + } + } + + @Override + public String toString() { + return "PacketOverwrite{" + "onlineValid=" + + onlineValid + + ", online=" + + online + + ", itemsValid=" + + itemsValid + + ", allItemUpdate=" + + allItemUpdate + + ", validIndices=" + + Arrays.toString(validIndices) + + ", items=" + + items + + ", entryId=" + + entryId + + '}'; + } + } + + /** + * Rename the entry. + */ + public static class PacketRename extends PacketEntry { + + public String newName; + + protected PacketRename(long id, String newName) { + super(id); + this.newName = newName; + } + + protected PacketRename(ByteBuf buf) throws IOException { + super(buf); + } + + @Override + protected void write(ByteBuf buf) { + buf.writeByte(PacketType.RENAME.ordinal()); + buf.writeLong(entryId); + ByteBufUtils.writeUTF8String(buf, newName); + } + + @Override + protected void read(ByteBuf buf) { + newName = ByteBufUtils.readUTF8String(buf); + } + + @Override + public String toString() { + return "PacketRename{" + "newName='" + newName + '\'' + ", entryId=" + entryId + '}'; + } + } +} diff --git a/src/main/java/com/glodblock/github/network/wrapper/FCIndexedCodec.java b/src/main/java/com/glodblock/github/network/wrapper/FCIndexedCodec.java new file mode 100644 index 000000000..9bb841a26 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/wrapper/FCIndexedCodec.java @@ -0,0 +1,32 @@ +package com.glodblock.github.network.wrapper; + +import appeng.core.AEConfig; +import appeng.core.AELog; +import appeng.core.features.AEFeature; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +public class FCIndexedCodec extends SimpleIndexedCodec { + + static int DISCRIMINATOR_BYTE = 1; + + @Override + public void encodeInto(ChannelHandlerContext ctx, IMessage msg, ByteBuf target) throws Exception { + super.encodeInto(ctx, msg, target); + + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info(" -> " + msg.getClass().getName() + " : " + target.readableBytes()); + } + } + + @Override + public void decodeInto(ChannelHandlerContext ctx, ByteBuf source, IMessage msg) { + if (AEConfig.instance.isFeatureEnabled(AEFeature.PacketLogging)) { + AELog.info(" <- " + msg.getClass().getName() + " : " + (source.readableBytes() + DISCRIMINATOR_BYTE)); + } + + super.decodeInto(ctx, source, msg); + } +} diff --git a/src/main/java/com/glodblock/github/network/wrapper/FCNetworkWrapper.java b/src/main/java/com/glodblock/github/network/wrapper/FCNetworkWrapper.java new file mode 100644 index 000000000..98963b515 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/wrapper/FCNetworkWrapper.java @@ -0,0 +1,177 @@ +package com.glodblock.github.network.wrapper; + +import java.util.EnumMap; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.INetHandler; +import net.minecraft.network.Packet; +import net.minecraft.tileentity.TileEntity; + +import com.google.common.base.Throwables; + +import cpw.mods.fml.common.network.FMLEmbeddedChannel; +import cpw.mods.fml.common.network.FMLOutboundHandler; +import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.SimpleChannelHandlerWrapper; +import cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec; +import cpw.mods.fml.relauncher.Side; +import io.netty.channel.ChannelFutureListener; + +/** + * Copied from {@link cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper} to be able to override IndexedCodec + * to add packet logging + */ +public class FCNetworkWrapper { + + protected final EnumMap channels; + protected final FCIndexedCodec packetCodec; + + public FCNetworkWrapper(String channelName) { + packetCodec = new FCIndexedCodec(); + channels = NetworkRegistry.INSTANCE.newChannel(channelName, packetCodec); + } + + /** + * Register a message and it's associated handler. The message will have the supplied discriminator byte. The + * message handler will be registered on the supplied side (this is the side where you want the message to be + * processed and acted upon). + * + * @param messageHandler the message handler type + * @param requestMessageType the message type + * @param discriminator a discriminator byte + * @param side the side for the handler + */ + public void registerMessage( + Class> messageHandler, Class requestMessageType, + int discriminator, Side side) { + registerMessage(instantiate(messageHandler), requestMessageType, discriminator, side); + } + + static IMessageHandler instantiate( + Class> handler) { + try { + return handler.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + + /** + * Register a message and it's associated handler. The message will have the supplied discriminator byte. The + * message handler will be registered on the supplied side (this is the side where you want the message to be + * processed and acted upon). + * + * @param messageHandler the message handler instance + * @param requestMessageType the message type + * @param discriminator a discriminator byte + * @param side the side for the handler + */ + public void registerMessage( + IMessageHandler messageHandler, Class requestMessageType, + int discriminator, Side side) { + packetCodec.addDiscriminator(discriminator, requestMessageType); + FMLEmbeddedChannel channel = channels.get(side); + String type = channel.findChannelHandlerNameForType(SimpleIndexedCodec.class); + if (side == Side.SERVER) { + addServerHandlerAfter(channel, type, messageHandler, requestMessageType); + } else { + addClientHandlerAfter(channel, type, messageHandler, requestMessageType); + } + } + + private void addServerHandlerAfter( + FMLEmbeddedChannel channel, String type, IMessageHandler messageHandler, + Class requestType) { + SimpleChannelHandlerWrapper handler = getHandlerWrapper(messageHandler, Side.SERVER, requestType); + channel.pipeline().addAfter(type, messageHandler.getClass().getName(), handler); + } + + private void addClientHandlerAfter( + FMLEmbeddedChannel channel, String type, IMessageHandler messageHandler, + Class requestType) { + SimpleChannelHandlerWrapper handler = getHandlerWrapper(messageHandler, Side.CLIENT, requestType); + channel.pipeline().addAfter(type, messageHandler.getClass().getName(), handler); + } + + private SimpleChannelHandlerWrapper getHandlerWrapper( + IMessageHandler messageHandler, Side side, Class requestType) { + return new SimpleChannelHandlerWrapper(messageHandler, side, requestType); + } + + /** + * Construct a minecraft packet from the supplied message. Can be used where minecraft packets are required, such as + * {@link TileEntity#getDescriptionPacket}. + * + * @param message The message to translate into packet form + * @return A minecraft {@link Packet} suitable for use in minecraft APIs + */ + public Packet getPacketFrom(IMessage message) { + return channels.get(Side.SERVER).generatePacketFrom(message); + } + + /** + * Send this message to everyone. The {@link IMessageHandler} for this message type should be on the CLIENT side. + * + * @param message The message to send + */ + public void sendToAll(IMessage message) { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL); + channels.get(Side.SERVER).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } + + /** + * Send this message to the specified player. The {@link IMessageHandler} for this message type should be on the + * CLIENT side. + * + * @param message The message to send + * @param player The player to send it to + */ + public void sendTo(IMessage message, EntityPlayerMP player) { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET) + .set(FMLOutboundHandler.OutboundTarget.PLAYER); + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player); + channels.get(Side.SERVER).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } + + /** + * Send this message to everyone within a certain range of a point. The {@link IMessageHandler} for this message + * type should be on the CLIENT side. + * + * @param message The message to send + * @param point The {@link TargetPoint} around which to send + */ + public void sendToAllAround(IMessage message, TargetPoint point) { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET) + .set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT); + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point); + channels.get(Side.SERVER).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } + + /** + * Send this message to everyone within the supplied dimension. The {@link IMessageHandler} for this message type + * should be on the CLIENT side. + * + * @param message The message to send + * @param dimensionId The dimension id to target + */ + public void sendToDimension(IMessage message, int dimensionId) { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET) + .set(FMLOutboundHandler.OutboundTarget.DIMENSION); + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(dimensionId); + channels.get(Side.SERVER).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } + + /** + * Send this message to the server. The {@link IMessageHandler} for this message type should be on the SERVER side. + * + * @param message The message to send + */ + public void sendToServer(IMessage message) { + channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET) + .set(FMLOutboundHandler.OutboundTarget.TOSERVER); + channels.get(Side.CLIENT).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } +} diff --git a/src/main/java/com/glodblock/github/proxy/CommonProxy.java b/src/main/java/com/glodblock/github/proxy/CommonProxy.java index 2662b4c01..efec9d61c 100644 --- a/src/main/java/com/glodblock/github/proxy/CommonProxy.java +++ b/src/main/java/com/glodblock/github/proxy/CommonProxy.java @@ -13,23 +13,21 @@ import com.glodblock.github.inventory.external.AEFluidInterfaceHandler; import com.glodblock.github.loader.ItemAndBlockHolder; import com.glodblock.github.network.SPacketMEUpdateBuffer; +import com.glodblock.github.network.wrapper.FCNetworkWrapper; import com.glodblock.github.util.ModAndClassUtil; import appeng.api.AEApi; import appeng.api.IAppEngApi; import appeng.api.config.Upgrades; -import appeng.helpers.InterfaceTerminalSupportedClassProvider; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLLoadCompleteEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; -import cpw.mods.fml.common.network.NetworkRegistry; -import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; public class CommonProxy { - public final SimpleNetworkWrapper netHandler = NetworkRegistry.INSTANCE.newSimpleChannel(FluidCraft.MODID); + public final FCNetworkWrapper netHandler = new FCNetworkWrapper(FluidCraft.MODID); public void preInit(FMLPreInitializationEvent event) {} @@ -68,9 +66,9 @@ public void postInit(FMLPostInitializationEvent event) { Upgrades.CRAFTING.registerItem(new ItemStack(ItemAndBlockHolder.FLUID_EXPORT_BUS), 1); } AEApi.instance().registries().externalStorage().addExternalStorageInterface(new AEFluidInterfaceHandler()); - InterfaceTerminalSupportedClassProvider.register(PartFluidP2PInterface.class); - InterfaceTerminalSupportedClassProvider.register(PartFluidInterface.class); - InterfaceTerminalSupportedClassProvider.register(TileFluidInterface.class); + AEApi.instance().registries().interfaceTerminal().register(PartFluidP2PInterface.class); + AEApi.instance().registries().interfaceTerminal().register(PartFluidInterface.class); + AEApi.instance().registries().interfaceTerminal().register(TileFluidInterface.class); } public void onLoadComplete(FMLLoadCompleteEvent event) {} diff --git a/src/main/java/com/glodblock/github/util/FCGuiColors.java b/src/main/java/com/glodblock/github/util/FCGuiColors.java new file mode 100644 index 000000000..c9c2e9546 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FCGuiColors.java @@ -0,0 +1,46 @@ +package com.glodblock.github.util; + +import net.minecraft.util.StatCollector; + +import appeng.core.AELog; + +public enum FCGuiColors { + + // ARGB Colors: Name and default value + StateNone(0x00000000), + StateIdle(0xFF55FF55), + StateCraft(0xFFFFFF55), + StateExport(0xFFAA00AA), + StateError(0xFFFF5555); + + private final String root; + private final int color; + + FCGuiColors() { + this.root = "ae2fc.gui.color"; + this.color = 0x000000; + } + + FCGuiColors(final int hex) { + this.root = "ae2fc.gui.color"; + this.color = hex; + } + + public int getColor() { + String hex = StatCollector.translateToLocal(this.getUnlocalized()); + int color = this.color; + + if (hex.length() <= 8) { + try { + color = Integer.parseUnsignedInt(hex, 16); + } catch (final NumberFormatException e) { + AELog.warn("Couldn't format color correctly for: " + this.root + " -> " + hex); + } + } + return color; + } + + public String getUnlocalized() { + return this.root + '.' + this.toString(); + } +} diff --git a/src/main/java/com/glodblock/github/util/NameConst.java b/src/main/java/com/glodblock/github/util/NameConst.java index 350f651db..f5644bfac 100644 --- a/src/main/java/com/glodblock/github/util/NameConst.java +++ b/src/main/java/com/glodblock/github/util/NameConst.java @@ -26,6 +26,7 @@ public class NameConst { public static final String ITEM_PART_FLUID_STORAGE_MONITOR = "part_fluid_storage_monitor"; public static final String ITEM_PART_FLUID_CONVERSION_MONITOR = "part_fluid_conversion_monitor"; public static final String ITEM_PART_FLUID_TERMINAL = "part_fluid_terminal"; + public static final String ITEM_PART_LEVEL_TERMINAL = "part_level_terminal"; public static final String ITEM_PART_FLUID_PATTERN_TERMINAL = "part_fluid_pattern_terminal"; public static final String ITEM_PART_FLUID_PATTERN_TERMINAL_EX = "part_fluid_pattern_terminal_ex"; public static final String ITEM_PART_FLUID_INTERFACE = "part_fluid_interface"; @@ -43,6 +44,7 @@ public class NameConst { public static final String ITEM_FLUID_PORTABLE_CELL = "portable_fluid_cell"; public static final String ITEM_WIRELESS_FLUID_TERMINAL = "wireless_fluid_terminal"; public static final String ITEM_WIRELESS_INTERFACE_TERMINAL = "wireless_interface_terminal"; + public static final String ITEM_WIRELESS_LEVEL_TERMINAL = "wireless_level_terminal"; public static final String ITEM_WIRELESS_ULTRA_TERMINAL = "wireless_ultra_terminal"; public static final String ITEM_WIRELESS_FLUID_PATTERN_TERMINAL = "wireless_fluid_pattern_terminal"; public static final String ITEM_FLUID_PART = "fluid_part"; @@ -50,6 +52,7 @@ public class NameConst { public static final String TT_KEY = FluidCraft.MODID + ".tooltip."; public static final String TT_FLUID_TERMINAL = TT_KEY + "fluid_terminal"; + public static final String TT_LEVEL_TERMINAL = TT_KEY + "level_terminal"; public static final String TT_INVALID_FLUID = TT_KEY + "invalid_fluid"; public static final String TT_FLUID_PACKET = TT_KEY + "fluid_packet"; public static final String TT_ENCODE_PATTERN = TT_KEY + "encode_pattern"; @@ -79,6 +82,8 @@ public class NameConst { public static final String TT_LEVEL_MAINTAINER_LINK_DESC = TT_LEVEL_MAINTAINER + "link_desc"; public static final String TT_LEVEL_MAINTAINER_EXPORT = TT_LEVEL_MAINTAINER + "export"; public static final String TT_LEVEL_MAINTAINER_EXPORT_DESC = TT_LEVEL_MAINTAINER + "export_desc"; + public static final String TT_LEVEL_MAINTAINER_ERROR = TT_LEVEL_MAINTAINER + "error"; + public static final String TT_LEVEL_MAINTAINER_ERROR_DESC = TT_LEVEL_MAINTAINER + "error_desc"; public static final String TT_CELL_CONTENTS = TT_KEY + "cell_contents"; public static final String TT_CELL_EMPTY = TT_KEY + "cell_empty"; public static final String TT_CELL_PORTABLE = TT_KEY + "cell_portable"; @@ -101,6 +106,7 @@ public class NameConst { public static final String GUI_FLUID_PATTERN_TERMINAL = GUI_KEY + ITEM_PART_FLUID_PATTERN_TERMINAL; public static final String GUI_FLUID_PATTERN_TERMINAL_EX = GUI_KEY + ITEM_PART_FLUID_PATTERN_TERMINAL_EX; public static final String GUI_LEVEL_MAINTAINER = GUI_KEY + BLOCK_LEVEL_MAINTAINER; + public static final String GUI_LEVEL_TERMINAL = GUI_KEY + ITEM_PART_LEVEL_TERMINAL; public static final String GUI_FLUID_PATTERN_ENCODER = GUI_KEY + BLOCK_FLUID_PATTERN_ENCODER; public static final String GUI_FLUID_PACKET_DECODER = GUI_KEY + BLOCK_FLUID_PACKET_DECODER; public static final String GUI_FLUID_AUTO_FILLER = GUI_KEY + BLOCK_FLUID_AUTO_FILLER; diff --git a/src/main/resources/assets/ae2fc/lang/en_US.lang b/src/main/resources/assets/ae2fc/lang/en_US.lang index 58ebb3415..58ae1a029 100644 --- a/src/main/resources/assets/ae2fc/lang/en_US.lang +++ b/src/main/resources/assets/ae2fc/lang/en_US.lang @@ -11,13 +11,16 @@ item.part_fluid_storage_bus.name=ME Fluid Storage Bus item.part_fluid_level_emitter.name=ME Fluid Level Emitter item.part_fluid_storage_monitor.name=ME Fluid Storage Monitor item.part_fluid_conversion_monitor.name=ME Fluid Conversion Monitor +item.part_level_terminal.name=ME Level Terminal item.portable_fluid_cell.name=Portable Fluid Cell item.wireless_fluid_terminal.name=Wireless Fluid Terminal +item.wireless_level_terminal.name=Wireless Level Terminal item.wireless_fluid_pattern_terminal.name=Wireless Fluid Pattern Terminal item.wireless_interface_terminal.name=Wireless Interface Terminal item.wireless_ultra_terminal.WIRELESS_CRAFTING_TERMINAL.name=Universal Wireless Terminal - Crafting item.wireless_ultra_terminal.WIRELESS_FLUID_PATTERN_TERMINAL.name=Universal Wireless Terminal - Pattern item.wireless_ultra_terminal.WIRELESS_FLUID_TERMINAL.name=Universal Wireless Terminal - Fluid +item.wireless_ultra_terminal.WIRELESS_LEVEL_TERMINAL.name=Universal Wireless Terminal - Level item.wireless_ultra_terminal.WIRELESS_ESSENTIA_TERMINAL.name=Universal Wireless Terminal - Essentia item.wireless_ultra_terminal.WIRELESS_INTERFACE_TERMINAL.name=Universal Wireless Terminal - Interface item.wireless_ultra_terminal.WIRELESS_FLUID_PATTERN_TERMINAL_EX.name=Universal Wireless Terminal - Processing Pattern @@ -90,6 +93,8 @@ ae2fc.tooltip.level_maintainer.link=§eCrafting§r ae2fc.tooltip.level_maintainer.link_desc=The system is currently crafting the requested item or fluid. ae2fc.tooltip.level_maintainer.export=§5Exporting§r ae2fc.tooltip.level_maintainer.export_desc=The Requester is trying to export the crafting results to the system. If the Requester has this status for a long time, there is no available space for the export. +ae2fc.tooltip.level_maintainer.error=§4Errored§r +ae2fc.tooltip.level_maintainer.error_desc=The Requester is trying to schedule a crafting job but is failing. Possible reasons include a missing recipe or insufficient resources. ae2fc.tooltip.level_maintainer.batch_size=§6Crafting Batch Size§r ae2fc.tooltip.level_maintainer.batch_size.hint=When craft requests are emitted, the Requester will use the batch size for the request. Using larger batches will increase the speed of stocking up items but will require more crafting storage. ae2fc.tooltip.level_maintainer.request_size=§6Amount to Maintain§r @@ -97,6 +102,7 @@ ae2fc.tooltip.level_maintainer.request_size.hint=The count defines how many item ae2fc.tooltip.ultra_terminal.WIRELESS_CRAFTING_TERMINAL=Mode: Crafting Terminal ae2fc.tooltip.ultra_terminal.WIRELESS_FLUID_PATTERN_TERMINAL=Mode: Pattern Terminal ae2fc.tooltip.ultra_terminal.WIRELESS_FLUID_TERMINAL=Mode: Fluid Terminal +ae2fc.tooltip.ultra_terminal.WIRELESS_LEVEL_TERMINAL=Mode: Level Terminal ae2fc.tooltip.ultra_terminal.WIRELESS_ESSENTIA_TERMINAL=Mode: Essentia Terminal ae2fc.tooltip.ultra_terminal.WIRELESS_INTERFACE_TERMINAL=Mode: Interface Terminal ae2fc.tooltip.ultra_terminal.WIRELESS_FLUID_PATTERN_TERMINAL_EX=Mode: Processing Pattern Terminal @@ -108,6 +114,7 @@ ae2fc.tooltip.cell_contents=Contains Fluid: ae2fc.tooltip.cell_empty=Cell is empty ae2fc.tooltip.cell_portable=Right click to open its GUI. It works like a backpack, but you need to charge it before using. ae2fc.tooltip.fluid_terminal=uh So we don't need EC2 anymore? +ae2fc.tooltip.level_terminal=uh... ae2fc.tooltip.invalid_fluid=Invalid fluid! ae2fc.tooltip.encode_pattern=Encode Pattern ae2fc.tooltip.fluid_packet=Use a Fluid Packet Decoder to\nconvert this back into fluid. @@ -123,6 +130,7 @@ ae2fc.tooltip.craft_terminal_w=Crafting Terminal ae2fc.tooltip.pattern_terminal_w=Pattern Terminal ae2fc.tooltip.essentia_terminal_w=Essentia Terminal ae2fc.tooltip.interface_terminal_w=Interface Terminal +ae2fc.tooltip.level_terminal_w=Level Terminal ae2fc.tooltip.pattern_terminal_ex_w=Processing Pattern Terminal ae2fc.tooltip.wireless.installed=Installed Card: @@ -134,13 +142,17 @@ ae2fc.tooltip.submit=Submit ae2fc.tooltip.enable=Enabled ae2fc.tooltip.disable=Disabled ae2fc.tooltip.edit=Edit +ae2fc.tooltip.view=View ae2fc.tooltip.fill_pattern=Allow auto fill blank pattern ae2fc.tooltip.not_fill_pattern=Allow auto fill blank pattern ae2fc.tooltip.fill_pattern.hint=Enabled ae2fc.tooltip.not_fill_pattern.hint=Disabled +ae2fc.tooltip.open_configuration=Open configuration +ae2fc.tooltip.block_highlight=Highlight Block ae2fc.gui.part_fluid_pattern_terminal=Fluid Pattern Terminal ae2fc.gui.part_fluid_pattern_terminal_ex=Fluid Processing Pattern Terminal +ae2fc.gui.part_level_terminal=Level Terminal ae2fc.gui.fluid_pattern_encoder=Fluid Pattern Encoder ae2fc.gui.fluid_packet_decoder=ME Fluid Packet Decoder ae2fc.gui.ingredient_buffer=Ingredient Buffer @@ -162,6 +174,12 @@ ae2fc.gui.part_fluid_terminal=ME Fluid Terminal ae2fc.gui.part_fluid_storage_bus=ME Fluid Storage Bus ae2fc.gui.fluid_auto_filler=ME Fluid Auto Filler +ae2fc.gui.color.StateNone=00000000 +ae2fc.gui.color.StateIdle=FF55FF55 +ae2fc.gui.color.StateCraft=FFFFFF55 +ae2fc.gui.color.StateExport=FFAA00AA +ae2fc.gui.color.StateError=FFFF5555 + error.unknown=Unknown key.OpenTerminal=Open Wireless Universal Terminal diff --git a/src/main/resources/assets/ae2fc/textures/blocks/level_terminal_bright.png b/src/main/resources/assets/ae2fc/textures/blocks/level_terminal_bright.png new file mode 100644 index 0000000000000000000000000000000000000000..fa8156bd50fc690cc3c9cb8555a272cca35b841d GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|ygXeTLoEE0 zQx*sq1g)5#C?NIWKM?%bbM(ZCjz?KM`UiLzG+8z#nw$w(#N!aoa;YcBU=w%yYVH+6 p+&g#_CAgQUy>*;1#q%o@Lv^Er;1`KA_CQk^JYD@<);T3K0RZC~FE0Q9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ae2fc/textures/blocks/level_terminal_dark.png b/src/main/resources/assets/ae2fc/textures/blocks/level_terminal_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..44e4c64ffd4a6fa62f064b958fc58c5a36b28b1a GIT binary patch literal 1427 zcmbVM%WKp?9FA7oTH4~V2;z_;D4JxFeP(DZZML=xrY`M5D_)$P%9v1@2d_e%>?5>VD>g8h*Eiqq{oAW7FHVeI8IvSwqP$dE z5%c9_j1G(cwI7FAOqar?2eBkgzD~xukyon+l5}z0tFH5P=N=-=SFy`#RPFeoKuglh zY$wEIgK|)#4KJ|d?;k(Qz;i8mE$2Wdv}w~@+KK4u&T^IPY!K6xXYYWS4iW@Du9BPw=YZVEV;>fh%~L;ZmaE#%A$s*o2IEjLo*CTAe4AJ;JBj% z@$`V9L}L9K;+4gqBN|ES#cxo{New=R%@G zg}PK%ayVO5YNSXNT+7!B6y{(io4zkGvYCW_@ZSB;_xB@Dlpb!KnI|d8Bxlf)7mH|a z_e*A#KJKqt9_XeC!X!z5OD0L&sVn!7y)%2DN84^vL3&C?^k6Zo^EQs?Ttj&4ANi&U z)wQHddsb+_8`!-&Qqlvs=o85@ZBSy9wm2Gyz7~lFcK++TebM}sa%rwwd_jI59?lM3 z-`$fBKEU0n!#8i|3cD{yhbsHypWsw(cWn6imuDBGCzB&rGY`M{N!u(hESKKTKYIEL DnAW@{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ae2fc/textures/blocks/level_terminal_medium.png b/src/main/resources/assets/ae2fc/textures/blocks/level_terminal_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..a24af7d7056fcd3b36935109411eb26825854163 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|!aZFaLoEE0 zQx*sq1g)6g_>1k&|NsB(?ZOR>j21<79b(LM3vbAi*d;ZG?SROlY=u({IrkcN_GmCW zoRfQ`cR;+?rJYgF`GXV#x6LMDAgTe~DWM4f D3r#X` literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ae2fc/textures/gui/level_maintainer.png b/src/main/resources/assets/ae2fc/textures/gui/level_maintainer.png index 1e3e15c44d2d7da65d52a5353bc127b6f74bf68a..e515e9268609cbddf25a4aeb26712f10d1f0b0a5 100644 GIT binary patch literal 4044 zcmeH~do)yQAIG1)ZQ1VIC5nu}jL5B0xg3{`AtL0Oh$%@)B~e2z8x`Fcl}n{elT#v> zQiGDF=#b=ciYP)MHF4x}Qb+afTGe}c&wJi?t+Uoy??3OJKc0D>`K`U4`TjoN@3Z$l zSLdaYVoG8F07(aXh8qA7`4s}_407-b&tLy(w%u*1H7IVH^8x_ry$%d350?LM&Vuj< zO|r>ZHkhe~8m)hpv)^qxs-4=Kt;{~`I^Z~kVr-LsEbdBNb6jB%J@U=;**1-M=c$i{ z>sOsA@$KPVE{xhf^|9yKo%r!wEZ?bj`M~W%mwCbLw6rw8j~eum#U+#XPMo`B3n!`@ zTlYUzBxnpuLeGtO)h9RN(-5ToqYVH3`|DI)HEK&5zq`BJef05TUs_8_lseG=V0YZf zMU4Ov*)l{bJ^e6B1u7d5PM|{`4MuShC1_}+toA+twP}BV5nNYs9htkyJW((p{w;TS9jJ_RzKIo|$ zShefTh<2*F|9Bz;GA_}scc-AZ$2#Agpe~Q{xH9v`i4!MkNJRpW(Y~7G%&?%rxVK|_ z#!c`1q%DoKlsny1!TaUjOdpYi{G2u6>~Jd(Yw+&=kUqq++}13v3{ipOMhzfNzc&lv z^mWMZks_ox=LscE4PpkX;5-VT{E$1!A`oj|HLUy$+Q4V?19zM$!#;zNg$L>no3AM}JN~uXmCZar<3b^1fOQj;C zS8yy1jD?@nBsPd_OI=&ya(CR#;-~Z}1?pUvjc~n*O6nye*bI4fqID6ZMR{~F(yM2! z>(aEr1Iffor^Y(RnLrvcn5+KoNN3f;eJa|~{$@fcuTvWric`l#n=+ZaqYMLi--%&6 z+h%d7f1r^Le(?MaZO;~ui7E{DZ^Cejpi{%v;3(`E;Aj1LZM_Um*@W;P z6T$_XuOf&mmEP*o06U%&%0IO`V^WQPMH%2eEliy4eH5jpEiMOLuzdcKEl>kJfov1A zkeesev48r`HW>hS6i6h`Bwh}1i}<;!J4*~qY?}{cC4|r0z7p#1?bGs=>kZ;m&&EOQ zTiNUB0N#L9JTHNM>7Fi(){yL6(8HCtKiDc%U|(FfK%5%gd@qwJaA4LR1wC-T=WZWRB_>Zu&ci&WM)XcUs4-f#{vLJ!*drrGWoep`61La=q?%dFIskvyn;q zxuK}n3tgRqq;!ZmW^;lz!Br9ujD&vY=Qq=Oc)%h?&nG1Z(~Wk5)?Hh8$X&-l|J2%t zMAWfG;+#l_P|@~fqmzwGK~$x)9DX^8rT3pq%vd6CVmUda;2tZ(Tl&1}tV9&r;qTs# zo`;z>?7JKLvIuv5Goe!d>fvXNa7s*K89iIiij2CBdA61fbQ0G4b9-mWKvcpa;|gUa zbiweY1x(IHY?o{YNa@VCN1myZqvvdOGWs+KpD{A+be19Pxr^m&vtGnC${m0?q;n%r=lH-cB zQZ0h%bk>Ta10kH610X_o-%$pDhHwp_;;2rS!GUQDiq{>scR(;gY7yLWk>(~#mI@vE zyGu((L|UTrKb^GAxt6{)b5hCJO#{ab&Sil@*jT~qZqGK$1eaV3^VNL4 z_*$Q{<-r!OL|VcJbenB~6>nE{Z-J;XgdBJV_Dk_?#h{9?%}ZuMNUM%`)vCLz zH=9R*o9c_5Y`_frE_g~!TX-Lso-Q)Phz$91pzntA_iQS=iBePieR|tgjf4nJ3!w_< z*C@gB@uv!WX$Nh4r1$yOlL_ELUWIU2x;4=EJ0WQYtR@=ZlJ;Bx7-`ugq^v1SsEZ4>Xb~V?qGON>l+VT6X@5}zrLN4| zyAkDs7e8Z2sf6<#k#7x91C}(TH<))@0>Sc%bw@+=c3zom`Sx=w^qqPSI*o%8ynm}L z;!(b}j3LsSoF`9%N5{*XaNy+@@mB?2zmzj$;#Gf{gv;$@Db8to@3X}_KvA;Sh(wK) z*?4D%Ven^}oNT$Gf9law!)%+ zD)=uF$*X)NU_Oj;y%ktjGOs;~9{PrFh4842o0u##_0~6-3Usu$Kz?}`A^vcEk_?Vr z|3bTs$X7$u>Jh4k-PkC?BUx++KSSrR% zBQcu)Ef5NO;LDVd=4)-29AC#oYK=D)^NYOurl&ojQk~HtRzpc;LF_O7o6Tdy3D6-Q z@#BnNb!jAcq_8YCz9Be?RS2V(y2j_~lOl3wg(<K*_%~cI;Cx zUupQO^|(UcD`N^2wUORiS2~#p#whs%n%l&`=dKH`uvY_$#rI}t5Y%XL1Dh%fNfUkD z)IML5^dG4*MDC5q8F1-g(&%4uBYSm%a!c8XUly9pR5kr9YC|UTeTQtN9ON(3o?!du zFER++toZS@Yk7HjU3}`|#sD_ou&OTLMx07@{6~sJ%_6j44hO@HF2ir9CIt_FO<@o? z4C%*7_K*MiVuf6$7B=Kev2tA3FUaIbY3Z P2Ouv8TW3bGH8b%aDh_Cs literal 1376 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJD%bx#+^kcv5P?`$l*?IF>Y z=OE4_bG} z)k`%TerRz2u0Z1U+p^nt-p$*6{=0$ruHRpc_Wzmi^xSLSoh%GZoD3|&3><0<0zM21 zGZ-8U7#k9p7!JZEz9nb9o_+RMb#wizpFej-ufHDG;-toGP*q($`}MtuhO1dmr(`+S z^Bh>aXWzcKy_a?z`}_Cr_4(5e?K>Cm9(k4NLT%lg-N!Cp4*ve}Q!Y3BIVU-(>Yo+EyN3yttN2)U zK2_(quXXtAD%J|GPB-8Ozo$mQg;a zFk@nZz?sPn*n-(uXpJGzTR_#v_N_Rn%fMnR)bq^3IjDbPg2{29KVU9{n8LeZ{pag} z(ovl8W*{spR-8DJl`kZ@OpQVRA4~KA6#G ztnyWY)2(=p;!2pyjDbPp%a$bv_2UE=Br%#{$aNE#Vsuz2F;+GVOLVCIVfy8yv mihc2Qzygq1@Sr^Q`d{{>2}1AOZj>~Eba}e^xvXX^!VO$N4a4PS=;JI`7td z_x|ti-uLQ+mxqg{hJgkEK+|3c^)yaU2&%P}ycUh#PHjWjkz7 z40o?Ta%l3& zeycPkylYN!Uf+JN3Eb7yRX#P^S9?}WfGU>0S_~oaI@51owj7W>e||}br08IoeNX8* z6dIP5rwjXN(=hWW;R<9mjO6fg9Yel?5$4{je@JIJV_>xh2i@k1fzpbOOXT|~ne`7> zjWly2S$taPuM6u#@O>NC%ZG;ap)SgdtD(? z9VV)*ti048pfzal!l1h9C3>-_sH(E6>Y$b&QyzDxB`$6)OvB`!ooU%D&~n5Sv-?Yo z(czT2>G5IP)cLvFGs9JlF$>8P#}BGkn>}SVxPv;h|G)`~xNyWsM?Axf!i6nlO=X$E zkDN$nKT9voA=vnYy1;6x3f zq)~#K6c)lG#OVH8WuOICxsXKRdWI~P=s<}M>oPpRhVs53f}o)_3M~0s+56Okgv}?P zh4ndszrOvYKhG}B(lGT0(2(-JE@|RbYg5F}3tWUNCUsr+B}@t}(pt@+sSQIjH3r7^ zDLwLlply?zJ&O?js*Zpauoh8-LKh1P2946bLpqDByC)ZWd!8RWAW2#UPyaIL(*kjy zSmlcc2M4QykJq{Fw!~W1A9Eb7Cap1R3wW!99mBv06plv<{iQwlRXW=E$N}iHuZ-i| zbrMzJT)>&FV5*?A#!>SNRRJ4`V|u+w#aV}nu5=2{=npC~HRw3s+t=W8E^)@Oyb_MX z_@^ut(yjP}JABQt)cJR*@eFfhk;&Lp-@=5qtoRfM^fe?eCee?GeUYHX6nEfYijY~_ zgD&_YZU6ZqdjD;&f1mL4Gyl7W|GyeWmjS#-?~u#o-QQj&>t%_RO6ActNkiNE>^sj| z1;?C9=JBr0OJ+7kz7zTY%bhPSQ*2-ewt@H9!)e}l{}r^_SRvUg3}l1uQ>+j+oS)ej z1?V>iE|Q-*$P~@>$O(sh+3|;pLH~*K%7p2nxIpPb?@>M}I3jF6fBZ<_+Y%0axAx&UiBjOtNXV80lJzAnkKk-6D%+L8=yv7}qX z;_yA{WTt`lM=Wb%q-XulQdxFAh}W9y1XS2~Mt*o=4uZ&0UTwy+(kw}2n7^)i>=LwT*G zA=Y%bdDoa%E^3ccJkAbNXMva(-VekN98CaB1Mswy*xkXHbocK;gfU&Q4>mI{58eGE z^#qkA1^B`uO}*bV8WJKO3CPGi!Y=z$LiejxxLs}el+ZZ=Fa1u1{afgG64?O4vqaO> zTaHzqrl|8fug-FYuM-3rvox6NQY@84+#x*NH*A90Ge828WH^_bAi6CQRV-Vny{71t zE!;7{%b|+>K?*g|mhWl$n@S@9#Wngy-}mj2fT7#79Le&32}4aYA{{LQLdG3j1p}U0 zsQO1Z*;%Nxi3duq4y*M(i59Z<5{+2AGW!EzCKz~vQDD?fpC^ux)>#QxehN`;2hMz+ ztW-8opf{Gy?MrAoujHdLEn@NfHEqfIo+_yah^(}@`HKe@ z3>8T429+r+~F8q^q>)rhO*`bw}mwGP3 z_T!y4wWC)kYsHU)H%bEZV59f7_G-6ggAZmA;XIvcWuwnnPx+3rR#lRA@u(SWReDR}?;zpH{0hbyJ0I z8cRYkArwm%-AF5mBt!&-D2QDMmZ-#)cHy?Dh@t92Gz%d`sECUHHvR;y#>7GrHPO~e zQ)5jgCK0VRG30k{`Of4#@4NHvoo6P&F8W}|yf^pU`+etp=YQuVLLslBq9TQ*b#--- zkS4xmsoLAlbb^sXVZ3hLI^N^p!Gobmq-r0=Q3(XhLszX@MGqc4@buZ=m(4ly)1J{jA5~|wOdu6|JAvh@{OWgfti6Zm zn<^^_j{v-W<;oQ%;Q|c??d|PMq`to1BQRNe7lET4)pYDpA07K@vzx%aeft;?w0-~n zeVRLWZbBpkwElw-NX0&wK-~M~AAiWlt*mRaMu8)+Xn)ZnUYMJkn?OJZJ~%i?(7k>^ zLaEr>2*CRwfCwZd06+p_e0-ex`}=($;pwKPCMql}q_u0;@^2eAZsdCq2xBiBiaqX; zL#_xM{W70c{(R4w2VM>o7Z)=LApp>F0sQZ?XVa$x1GInteg-f1MMXuN#4dXswB*q4 z-MiTV_J15$qROv+A1;YS!)_$NusHs)tUc z{r?0sZ%&lF(Egng=lM4IEN{LCB0W8wNGTeR#fZOaS4-O;L5HjD+qXN>Mh){WMp{jQI#?? zGk+--i_z)Rr@8yyzJ2>m2*_T61;7X7^MV|;U|yWS2Qz2Vf|76P@#DwT)$#+qpB^EV zmPtRg4$-5o-arC7cI=>rh6Wx-;B9=;($YvNMd!|)qrSdADlILgTeoga4*^JMXlTUq zUPa|*x_kF7HD0^K&&HLafBFZh_vzo(2!Av-HZtgukr9prbDO(3^s%^K?H=-{zE zV1#hx5cd)3K@$KOgFgcK^Ht$TuL;aq_%%Iz_>ktjXz)nY-WzsG2n4*CE5&5CZQDk9 zd3m&K*)rW(j**lpTRC8^BI=kIDaDV>% zd6r8>MFra(KYpA*Y|oxO)Ya9MjDQ&l!5EG}aqbWU#r1R`o)1~?&hWhYW8;vMz>OO> zSo5b&oucQ@pK}7wnl+2c%gcEWM4-93*(M>8ig%u-k`M&)=c|&OS2Pxjm(7f{aeX6x z?y5qP#2|pr$&)9U01|uW&YhgpPk){~NfrU$nc7VV0tGorBqZL~cS9tO{4!##Lg)iG zZ{B3kqobn?c*~Y8v}@NcZ=24}PHJmwo2Dc#$WhOpy&#n^v&GMgDPmwfmMTbDGHvJlU?4n-oo1`{WY^(KQ7ir+DH zqSEM>%RY#J4jA9LCutL|l>i!!d9Z-Oa|~uEi9J0%=19!%0{R?e?gL`AwY5Brq8rOd zZ4xlOZIaQ6_#yxRG78HgiGK+00YI*RZps8OMqpjg`@oqqXLu6bv}u#C8w&xKr*UqO zj1maIgQko`Ho8YKkhQk9CP+vkAnyZ^lGx*YVCmAOyp7(Cbpk;$5%9WG-n+GnfGH(cLI)C%cUZj=iT)8{Y#1<*DO9noTeo^Tm)A+W2aEQl z27t^D-k4B^BK*kY(Jt_?V;~%*ojF%e>d9p7^==NbGWcCOv z0aPIzgiGqVUc+T0On;ole-@a4lwp7d3A_u7_jM3@6$61ohYtB_y{&PX)hJLx@Q_Fa zWbhpcDa0T#ye=9eu}1(ALZY5Hae_gi%i;q^U=Pz?2-qr+PTb6oz&;>AxkgTOUK|Pl zGS3I)fHX2aVyjoLX7Db1*C>&!Bl`%*%ZN@uXD?+`%BAxjUO#s2>bF_s%_YzH{!m=bk%@xajEUaCyZR2q39^6n~m(DV6&zTeirpd*#X% zCobtE^0P7^sC47Tjd<|j0rWl_iKO!N!iiE!=!$jRy?Yl&j~<1PNGhMm04m?GVFP-4 zdi>5P#ryZ~uWAns4WXr_1xe%w1_mrfbh*G3fS)7Bs1Ty^Lx&Dw&6+hlFFOV{r*DL+iMx443H^rZEeMg z6DR6cnp8fFiud6e(fh;Kk+Yx-ICbijYAjv4)T(%TdfGVcN##u-aYg>gxOJQ|;QICJ zShZ>u9zJ{+QcCpq_j9pf<;s=Vym_v3$eZB+2_{r)0Y|8!O+V|cf{w^{TsWf`< z;6c^cv111&CMJwZebSSY{x4^MX*7y#X5QB@VN4n-L`ET4j(=olYBh*JE@Q;l}dQ^>Q$AntbyPR#Ff`Q-bnJ0 zHQ;UOZp}5|kzO`A>3VHWu~SQ)WA3dOa~n-Q^dfpvV%V_7yMgh+b}f0MjO!+=up8!y z*&?X{*7HC;m<C*%pl&cAPbALW2F@M+sTzwhK=!TLfHY-)P_TBg-ZCWCUh zj5BA>ptsjnTPh=80%!(M1VF_(0A&DkUDwT84RBH^j7+7}{o8Zr;>(_IFfuZNr$ayD zt$(xwH1m1(j)U z&NQLy=B(~ja@FNz(r}z;50WH}$Y!%@ z@96ICR-vN@ST}!p)mEqdcwN(bw09&d$zAd4EKBTQ?^7 z%y*S|KWMQOX7nnb^Eav_=GdS-4W{8F|M>A^b#IcVT)pHG%tCxI6_AK{U)n)ZCeS!J z4~UGM2Z)_Jclu;ZFcCD3*V~~qsvkGZXOZW>IC08pA!rJn;Iohc1icKcvXmL1kPtA1 z0LNXpZ~+Gn9Przmsk3L#D(_RC7yF|^P+*IDwj)D`-jYni>E=K^{@Io|4}!AHFg!le z2$6^P)moRgg`g0$E$FH~y`g(tWRLv_kZwsV=h}UKMqtc*w zIG4+*W96nzn^c)V(l+@x-Zsrrl>yv^pFMjP>0Ldyn=%pQd6*G-66QHrPs29(AaNsE z+ZtfpCP7m95V08KeIo;serQc1&k(Z}c2)rR4=ylE2e|)h-~a#s07*qoM6N<$f;sJH AmH+?% diff --git a/src/main/resources/assets/ae2fc/textures/gui/states2.png b/src/main/resources/assets/ae2fc/textures/gui/states2.png new file mode 100644 index 0000000000000000000000000000000000000000..2018500d65a779660b9f2b24fd20ce31048d1e95 GIT binary patch literal 807 zcmV+?1K9kDP)Px%;Ymb6RA@u(n7?ZjK@`W|!rn!5U}dR)fuvJ=VGG4FAT|~TAr=M{#X`_RLBtag zk|F_#;e;b77AZsz4s6n>u@bu!g1Jhoz^S=g7 z!aVn{a&ZBdS612b{2WP)i;oXbF8a!|=WOZXg$&^8$D0iQ{^Z2NNd7DfPfH1b{fuI0eXsHol}vwcU`hPfGw_ zw;-BbD-y!Rqwq6ul#6)--@HNC0A%8`#?eEl;>G^V7eo=jnE1!*n{fT*wk``C;P`%} zsC%=;=u7FPWCEayN72CmxQNdHr24OpI#C>?7w0f2`uUwdF`Skt^7f$$|hcTyxt0vl`RxwyuWOGPtZ2T>h>qNr%h8nb|7 z6PK@B*fqM8tDf@wpzNF3{!N6P4lLWLa)4g1XZ&BP3Ao*Em;XAXMi>E5h-sy13UM5d znRGgxFac!2_!-y40I1PcVPue?GGK}{W+1POf&<7a6CqwMBLNc>fZU;KHgr7^B!I1W z1P&HJl#;HYC$5Cl3m`avR;x8K>vb2GI*o!UAq3D(AX9S(1E70K6y37{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ae2fc/textures/items/wireless_interface_terminal.png b/src/main/resources/assets/ae2fc/textures/items/wireless_interface_terminal.png index 93716a837fd87c782aeb1651df9a595ed465b5fd..fbf9a036f272471da44c090d9b63a750974a7331 100644 GIT binary patch delta 1137 zcmV-%1djXXnE{0fkR*Qrb5ch_0Itp)=>Px(KS@MERCr$Pn_EZ}Q5b;#-JP8oHwg+d zf^LwhS>%P#2&+w$E*4fAnNcZ(2)^`E5EMkF1U?A)&=Mjz~G{EF0P_omw(UD$m0FJYRo#VmI*(a_! z8@lFzvvFWUr_}~lbXu%nu}oT?rfHyRDyXUg3OW@TWOT}C^n+iPK$g*{U!QC(FxY(C zwHCwuJUA$QSmrRjExN z`F&8{oJkje?Z+^tP z*AQI*R{yMkB*6hq-N&YwKu`l*E>}cKP+MDz=OGQ~cyt?IzwUM8@%+|%;Ps6IU##B; zk6CwuYknPtB+&tvUsWa)zy;?+48T_So-P1uM~`CwjV}&|1(2GWI;|!Q4e4qYtS-6hLF~6AVDz)<+|N1yKL2EUo}ZC)ilr5dhFjBY^m8z*GQ~Y5?g2Hf5#ZUufUK zqZ1pUU>Jw94_KeJ5^Hp_Lxf-*ND2H~f(;cxt;Xt* zrmCO?o-3+u45)ylYI*~T`g#Ca5lR#QYAZryO)y%A7wP<9O|Z1dm{84nU%>QL;b3WB zfae6@QFFvD1R5j8<_Kzx=-r`UXDFmGqN;(e5NeEsG(`f<5L6DA{HQrXVPC*>ogvm9 zXYFy5x5rIy0+Gh;xiT;6zYmxzfua%6ms(KiorI7K2FDh^zOV0_d|#Gx z&pqef`#blZx%d8&7bhf+>k-gD0D_<%@o~|~;CnRp?%D->ZZ*w13%(w*#--UIC~y<^ z_FH;-3j;ypP*X}Oo0>3QOETHv1jQKWa7VTk)P^8kq{B*(Su`s#&>1F6g!HF9`=k;R z6(OChOh6K>W9dv&T%L`dn3tGB=4Fu@N*bvT&^ffgK{m}25=XY#V%It%q)xwD@S7`^ zNhQuIY*vIcifd4knlM2!ma)+iWjGF#2(FT-G~sfkN`MJ zl{CMk`T+1tXQPbT2%3@lw6v$pvC^_++Rn_jk#tNB7)pq*(c9T%+7q4oa0ROSbi|sBZTR6dZ9Hkx1=TMEON^{(kU!5s_9*s;#(DH%4|WTBW``*5ACwTWlq zc)Zck1WW6|#KvJn0n1e>2(FbY!Ni6UOp731PFyux`AA?WlW~sQhlcZk%2R-;T&+cc z=<(rIv$YSf5GjHs?#qjJT`xZrsWmdTY=YIBvWW~@X0>GKWS&B=nk~~)JC-psHqb3v zuh7YS75lV`X2{vx`iQcSv>gP)?iC~uDrW{5LuBwv-3qfw@5(Tmu^@jDTr{T#i#lQYA-ecSByz?rP|1n+ZG@2(womZY&fS3ymvO zN(C4TP7)ee4v@kcnj&DM+MvWK1Se3H#@&PuH+MA^XX4^Mr&SoZ*i58n@k>2%cV=)a zVYAa*eu|K~6I4se2US~MI%l5K5+s-V^(43IX-X&Km3q3>+RSu!IPVXE%fFX-+im1# z(w2K=4VNott+t)m86%rZ*yyMXu%7NGp}D;B&04$ny-ENh=gKsj+7Splk<-2~AULW~ zqe>jcXwnE18jSlu)G)15Vg^*HCI}3qqCXY}3@n}$khxKidzJ3Q`@ahV2i(;R)Hf?OvIz9H+~lJ@fW1!UI__pp3(orB-09rK>%nElU1eV0oVrx*%x<3TJdaA{V>am<;F|m5IxwTfsURK=oq3dpIBDgZA^|(^0Q0io@ zi(6YvFga**YP1R5ZP~e72OR90oHnf$J`K~_GW1e38@d*X*X6b|Fs@Q?bq;RrWi8kC zUNPhCAs?*Z8PS9F%kw5S!owjXh`59Z@$@1t9u6Tv#3e+Crx$VYa0m$^E+IlZy@-p4 zLr4&D2@&GyMO-`_LV}1(h!9UN;^N^D5=2}=gm`)p7Y~P!AmS1t#M6tocsPUv5tk4l zo?gVo!yzPyxP%Dt^dc@E4k1CrB}9m)7jf}$2nixCAwoR8h>M3qNDy%e5#s4ZTs#~? zf{06q5Kk}S;^7byL|j6IczO{R4~LK-;u0dn(~G!xID`Zdmk=SIUc|-2AtZ>ngb4BU zA}$^dAwk3?M2M#saq(~n2_h~bLOi{Qi-$uP+`_%8_+}Q!AbsI*2{8mK?Br&_@#oUi$KYreDI$)iY|}S^Z?cg`LO5 zV>2Z^l#4dsDbLvFsE8O<@w07L>4x=#r|mN%6^-@3-qHNn$@;DO;`1GAAT`u9;zHGO zW$M4Llsm<7fp5KC^Zl`}mZa{>g$6?Y`-?ga0-t{B-Ajig^^srva$OgvY~_?ST{}(* zZs=xTC9hv`q(K*009@QEg{u8uSiko1vw1608g)e#sA_ky?dl2p&JSfpm-1r{lqSx) z0_TSB-Oy*VE&pc6p5gN`?tA0t)uV#WB@LYS)Pd59@l7K^^<8snHNbe)rLb3L77qpf zDvKjk|7y@RjVegGwdLrr^^b2V+xA^U^{|`OMc0`L0Vze@s@DYJY5lf*sNNl;*;zg} z`LuBs`|{#K?bU-%*bnpvZKO4I>3mMRYp)WR0te`O!N7Ov;DTvovw!U!Qy3RIChXCW zqVcPq+_*CIMKk_#*zubczetXwUzs0`Ulq48IrPnavXi>owv4*cw^JU*NWdu-h${Hfe9xkOzInxw304jwF#hB|7G~C zvn6MPKpz_YPJh4P)7Nspa8y~Q%3Y1u{z*--k_vD zTTcCOBxCZDhAM2?v19RQQFl=Fl@%*`2QGa$rf^Z9wgSFfd(U74Xqc0veX%dx&_li#X?#BKBw)t5%I#yNeeYYlEwYz*; z*|eRz4qrcU;zYk4hBb4aU*2n3?5=mL&F;@KmWXX3{ZUY#nZ2K znAGUk$NwA}^nT&^CkpAu;#aB9)V)*s-pPV5x2tY#{o+hr3A^*3lCB;85jHWf4heey ztDZF#hjUMKd-L7o;eBGFR)vO?N36ScgT1pMzUs``m-dwRjq3Hvu$K9UuE2+}-Ed^wU!uy5OO~D?++<*t+%Suv@Da7w*0dUGAAb z156hX^-ZQO`xkc$y0N%x_q9#g-%Oo4wM)S!Q`oq@JJh@B$O8Y@^~r(RAj~IEp6mhD zrVe>FJ@NAJvTfV84bkqub`2Xzo*TaOqq=|(4qgA@)UgY;9#Dgt>GJl|*6M@v^@H`r z+x;Z3AK!uAc+Qr2(Rv-aN@c{Z41MTS_~;M6ErC9|?6>cYj?qc)riNXPS{Zum`#aU& zp0B?d45e54HI{TRLW2%;uOcq_<<)-%nacyPul=zB9iD+E_b#}-q@d&%zt3_O)lQlb zS+IOMlsefj{ijYP8Gct|Khf0>q5?k%U#Kl8sq9dF@~u4z2u*@pIGIrMBD|-eEnctWd5%Tf)0Yl2I^V8>Twmcu0H#9T2 ze{Jv#OZ{`F9|~?rC$=A5cIx~Q5Qc3fohPRs|7LIBJB=GZK}++dulyKtat+R{TH(^$*=)Px$lu1NER9Hu2WEfz;IKcKZ5bc1rQq5$Rq zQlfyW4jAxkh+Ys8QzTNgAR6$Zc)%*70k4h++yTTSHfpFLx>ZaK%dnXN0KD!vFzX~K Q!2kdN07*qoM6N<$f(v}XM*si- literal 0 HcmV?d00001