From 42098bd4cb854b678013a74bff48ced5c655f908 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 24 Sep 2025 20:11:30 +0800 Subject: [PATCH 1/7] Fixed structure description when holding shift. --- .../cubefury/vendingmachine/blocks/MTEVendingMachine.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 5181784..1ceb9c6 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -57,6 +57,7 @@ import gregtech.api.util.GTUtil; import gregtech.api.util.GTUtility; import gregtech.api.util.MultiblockTooltipBuilder; +import org.lwjgl.input.Keyboard; public class MTEVendingMachine extends MTEMultiBlockBase implements ISurvivalConstructable, ISecondaryDescribable, IAlignment { @@ -294,6 +295,7 @@ protected MultiblockTooltipBuilder getTooltip() { .beginStructureBlock(2, 3, 1, false) .addController("Middle") .addOtherStructurePart("Tin Item Pipe Casings", "Everything except the controller") + .addStructureInfo("Cannot be flipped onto its side") .toolTipFinisher(); } return tooltipBuilder; @@ -353,6 +355,11 @@ public String[] getSecondaryDescription() { return getTooltip().getStructureInformation(); } + @Override + public boolean isDisplaySecondaryDescription() { + return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); + } + @Override public void saveNBTData(NBTTagCompound aNBT) { super.saveNBTData(aNBT); From 02752506a057bc6b5a67cfaa0cb55e9e4b52f525 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 26 Sep 2025 17:03:25 +0800 Subject: [PATCH 2/7] Added vending uplink hatch --- .../vendingmachine/VendingMachine.java | 2 +- .../blocks/MTEVendingMachine.java | 141 +++++++++------ .../blocks/MTEVendingUplinkHatch.java | 167 ++++++++++++++++++ .../vendingmachine/items/VMItems.java | 6 + .../assets/vendingmachine/lang/en_US.lang | 1 + 5 files changed, 261 insertions(+), 56 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java diff --git a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java index 9041006..7ef5787 100644 --- a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java @@ -45,7 +45,7 @@ public class VendingMachine { public static boolean isAeLoaded = false; public static int CONTROLLER_MTE_ID = 2741; - // public static int ME_UPLINK_MTE_ID = 2742; + public static int ME_UPLINK_MTE_ID = 2742; @SidedProxy( clientSide = "com.cubefury.vendingmachine.ClientProxy", diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 1ceb9c6..8d1f0dc 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -1,9 +1,12 @@ package com.cubefury.vendingmachine.blocks; -import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; -import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static gregtech.api.casing.Casings.TinItemPipeCasing; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -20,6 +23,7 @@ import net.minecraftforge.common.util.ForgeDirection; import org.jetbrains.annotations.NotNull; +import org.lwjgl.input.Keyboard; import com.cleanroommc.modularui.utils.item.ItemStackHandler; import com.cubefury.vendingmachine.Config; @@ -45,22 +49,32 @@ import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; -import gregtech.api.GregTechAPI; import gregtech.api.covers.CoverRegistry; import gregtech.api.enums.Textures; +import gregtech.api.interfaces.IHatchElement; import gregtech.api.interfaces.ISecondaryDescribable; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.MTEMultiBlockBase; import gregtech.api.render.TextureFactory; +import gregtech.api.structure.IStructureInstance; +import gregtech.api.structure.IStructureProvider; +import gregtech.api.structure.StructureWrapper; +import gregtech.api.structure.StructureWrapperInstanceInfo; import gregtech.api.util.GTUtil; import gregtech.api.util.GTUtility; +import gregtech.api.util.IGTHatchAdder; import gregtech.api.util.MultiblockTooltipBuilder; -import org.lwjgl.input.Keyboard; public class MTEVendingMachine extends MTEMultiBlockBase - implements ISurvivalConstructable, ISecondaryDescribable, IAlignment { + implements ISurvivalConstructable, ISecondaryDescribable, IAlignment, IStructureProvider { + + public static final String[][] STRUCTURE = { { "cc", "c~", "cc" } }; + protected final StructureWrapper structure; + protected final StructureWrapperInstanceInfo structureInstanceInfo; + + private final ArrayList uplinkHatches = new ArrayList<>(); public static final int INPUT_SLOTS = 6; public static final int OUTPUT_SLOTS = 4; @@ -69,11 +83,6 @@ public class MTEVendingMachine extends MTEMultiBlockBase public static final int STRUCTURE_CHECK_TICKS = 20; - private static final IStructureDefinition STRUCTURE_DEFINITION = IStructureDefinition - .builder() - .addShape("main", new String[][] { { "cc", "c~", "cc" } }) - .addElement('c', lazy(t -> ofBlock(GregTechAPI.sBlockCasings11, 0))) - .build(); private static final ITexture[] FACING_SIDE = { TextureFactory.of(Textures.BlockIcons.MACHINE_CASING_ITEM_PIPE_TIN) }; private static final ITexture[] FACING_FRONT = { @@ -101,6 +110,18 @@ public class MTEVendingMachine extends MTEMultiBlockBase public MTEVendingMachine(final int aID, final String aName, final String aNameRegional) { super(aID, aName, aNameRegional); + + this.structure = new StructureWrapper<>(this); + this.structureInstanceInfo = null; + + this.structure.loadStructure(); + } + + protected MTEVendingMachine(MTEVendingMachine prototype) { + super(prototype.mName); + + this.structure = prototype.structure; + this.structureInstanceInfo = new StructureWrapperInstanceInfo<>(structure); } public void sendTradeRequest(TradeItemDisplay trade) { @@ -278,10 +299,6 @@ public boolean getDefaultHasMaintenanceChecks() { return false; } - public MTEVendingMachine(String aName) { - super(aName); - } - @Override public String[] getStructureDescription(ItemStack stackSize) { return getTooltip().getStructureHint(); @@ -425,7 +442,7 @@ public IAlignmentLimits getAlignmentLimits() { @Override public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { - return new MTEVendingMachine(this.mName); + return new MTEVendingMachine(this); } @Override @@ -434,18 +451,7 @@ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack a VendingMachine.LOG.warn("Check machine failed as Base MTE is null"); return false; } - return STRUCTURE_DEFINITION.check( - this, - "main", - getBaseMetaTileEntity().getWorld(), - getExtendedFacing(), - getBaseMetaTileEntity().getXCoord(), - getBaseMetaTileEntity().getYCoord(), - getBaseMetaTileEntity().getZCoord(), - 1, - 1, - 0, - !mMachine); + return structure.checkStructure(this); } @Override @@ -477,38 +483,12 @@ public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { @Override public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { if (mMachine) return -1; - return STRUCTURE_DEFINITION.survivalBuild( - this, - stackSize, - "main", - getBaseMetaTileEntity().getWorld(), - getExtendedFacing(), - getBaseMetaTileEntity().getXCoord(), - getBaseMetaTileEntity().getYCoord(), - getBaseMetaTileEntity().getZCoord(), - 1, - 1, - 0, - elementBudget, - env, - false); + return structure.survivalConstruct(this, stackSize, elementBudget, env); } @Override public void construct(ItemStack stackSize, boolean hintsOnly) { - STRUCTURE_DEFINITION.buildOrHints( - this, - stackSize, - "main", - getBaseMetaTileEntity().getWorld(), - getExtendedFacing(), - getBaseMetaTileEntity().getXCoord(), - getBaseMetaTileEntity().getYCoord(), - getBaseMetaTileEntity().getZCoord(), - 1, - 1, - 0, - hintsOnly); + structure.construct(this, stackSize, hintsOnly); } @Override @@ -577,4 +557,55 @@ public void spawnItem(ItemStack stack) { itemEntity.motionZ = 0.05f * offsetZ; world.spawnEntityInWorld(itemEntity); } + + @Override + public String[][] getDefinition() { + return STRUCTURE; + } + + @Override + public IStructureDefinition compile(String[][] definition) { + structure.addCasing('c', TinItemPipeCasing) + .withHatches(1, 1, Collections.singletonList(VendingUplinkHatchAdder.INSTANCE)); + return structure.buildStructure(definition); + } + + @Override + public IStructureInstance getStructureInstance() { + return this.structureInstanceInfo; + } + + private enum VendingUplinkHatchAdder implements IHatchElement { + + INSTANCE; + + @Override + public List> mteClasses() { + return Arrays.asList(MTEVendingUplinkHatch.class); + } + + @Override + public IGTHatchAdder adder() { + return (vm, hatchTE, aBaseCasingIndex) -> { + if (hatchTE == null || hatchTE.isDead()) return false; + + IMetaTileEntity aMetaTileEntity = hatchTE.getMetaTileEntity(); + + if (aMetaTileEntity == null) return false; + + if (!(aMetaTileEntity instanceof MTEVendingUplinkHatch uplinkHatch)) return false; + + vm.uplinkHatches.add(uplinkHatch); + uplinkHatch.updateTexture(aBaseCasingIndex); + uplinkHatch.updateCraftingIcon(uplinkHatch.getMachineCraftingIcon()); + + return true; + }; + } + + @Override + public long count(MTEVendingMachine mteVendingMachine) { + return mteVendingMachine.uplinkHatches.size(); + } + } } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java new file mode 100644 index 0000000..aa8a174 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -0,0 +1,167 @@ +package com.cubefury.vendingmachine.blocks; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_INPUT_FLUID_HATCH; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_INPUT_FLUID_HATCH_ACTIVE; + +import java.util.EnumSet; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraftforge.common.util.ForgeDirection; + +import com.cubefury.vendingmachine.VendingMachine; +import com.cubefury.vendingmachine.items.VMItems; + +import appeng.api.implementations.IPowerChannelState; +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.util.AECableType; +import appeng.api.util.DimensionalCoord; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.MTEHatch; +import gregtech.api.render.TextureFactory; + +public class MTEVendingUplinkHatch extends MTEHatch implements IGridProxyable, IPowerChannelState { + + protected AENetworkProxy gridProxy = null; + protected boolean additionalConnection = false; + + public static final int mTier = 3; + + public MTEVendingUplinkHatch(int aID, String aName, String aNameRegional) { + super( + aID, + aName, + aNameRegional, + mTier, + 0, + new String[] { "Vending Machine Uplink hatch.", "Uses inputs directly from ME network." }); + } + + public MTEVendingUplinkHatch(MTEVendingUplinkHatch prototype) { + super(prototype.mName, prototype.mTier, 0, prototype.mDescriptionArray, prototype.mTextures); + } + + @Override + public void onFacingChange() { + updateValidGridProxySides(); + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public AENetworkProxy getProxy() { + if (gridProxy == null) { + if (getBaseMetaTileEntity() instanceof IGridProxyable) { + gridProxy = new AENetworkProxy(this, "proxy", VMItems.uplinkHatch, true); + gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL); + updateValidGridProxySides(); + if (getBaseMetaTileEntity().getWorld() != null) { + gridProxy.setOwner( + getBaseMetaTileEntity().getWorld() + .getPlayerEntityByName(getBaseMetaTileEntity().getOwnerName())); + } + } + } + return this.gridProxy; + } + + @Override + public boolean isPowered() { + return getProxy() != null && getProxy().isPowered(); + } + + @Override + public boolean isActive() { + return getProxy() != null && getProxy().isActive(); + } + + @Override + public DimensionalCoord getLocation() { + return new DimensionalCoord( + getBaseMetaTileEntity().getWorld(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord()); + } + + @Override + public IGridNode getGridNode(ForgeDirection dir) { + return getProxy().getNode(); + } + + @Override + public void securityBreak() {} + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_FLUID_HATCH_ACTIVE) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_FLUID_HATCH) }; + } + + @Override + public AECableType getCableConnectionType(ForgeDirection forgeDirection) { + return isOutputFacing(forgeDirection) ? AECableType.SMART : AECableType.NONE; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTEVendingUplinkHatch(this); + } + + @Override + public void onFirstTick(IGregTechTileEntity baseMetaTileEntity) { + super.onFirstTick(baseMetaTileEntity); + getProxy().onReady(); + } + + private void updateValidGridProxySides() { + if (additionalConnection) { + getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); + } else { + getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + } + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ, ItemStack aTool) { + additionalConnection = !additionalConnection; + updateValidGridProxySides(); + aPlayer.addChatComponentMessage( + new ChatComponentTranslation("GT5U.hatch.additionalConnection." + additionalConnection)); + return true; + } + + public boolean hasItem() { + IStorageGrid storage = null; + try { + storage = getProxy().getStorage(); + } catch (GridAccessException gae) { + VendingMachine.LOG.info(gae); + gae.printStackTrace(); + return false; + } + return storage == null; + } + +} diff --git a/src/main/java/com/cubefury/vendingmachine/items/VMItems.java b/src/main/java/com/cubefury/vendingmachine/items/VMItems.java index 5b478b5..27e06a7 100644 --- a/src/main/java/com/cubefury/vendingmachine/items/VMItems.java +++ b/src/main/java/com/cubefury/vendingmachine/items/VMItems.java @@ -4,12 +4,14 @@ import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.blocks.MTEVendingMachine; +import com.cubefury.vendingmachine.blocks.MTEVendingUplinkHatch; import cpw.mods.fml.common.Optional; public class VMItems { public static ItemStack vendingMachine; + public static ItemStack uplinkHatch; public VMItems() {} @@ -19,5 +21,9 @@ public static void registerMultis() { VendingMachine.CONTROLLER_MTE_ID, "multimachine.vendingmachine", "Vending Machine").getStackForm(1); + uplinkHatch = new MTEVendingUplinkHatch( + VendingMachine.ME_UPLINK_MTE_ID, + "hatch.vendinguplink.me", + "ME Vending Uplink Hatch").getStackForm(1); } } diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 47b908a..70de284 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -23,6 +23,7 @@ vendingmachine.gui.cooldown_display.day=d vendingmachine.gui.error.player_using=Someone is using the vending machine at the moment. gt.blockmachines.multimachine.vendingmachine.name=Vending Machine +hatch.vendinguplink.me.name=ME Vending Uplink Hatch vendingmachine.category.unknown=Unknown Category vendingmachine.category.all=All Items From d4582bb8cb4a1666b4031ff4cd7ed2dd6e630b14 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 27 Sep 2025 13:18:52 +0800 Subject: [PATCH 3/7] Fixed trades with no conditions not showing up. --- .../network/handlers/NetAvailableTradeSync.java | 2 +- .../vendingmachine/trade/TradeGroup.java | 6 +++++- .../vendingmachine/trade/TradeManager.java | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java index 7f84010..455d2d4 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java @@ -59,7 +59,7 @@ public static void onServer(Tuple2 message) { @SideOnly(Side.CLIENT) public static void onClient(NBTTagCompound message) { - if ( // Don't sync in SP or LAN - will delete other player's data + if ( // Don't sync in LAN - will delete other player's data Minecraft.getMinecraft() .isIntegratedServerRunning() ) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index 5702483..d02df8d 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -51,6 +51,10 @@ public String toString() { return this.id.toString(); } + public boolean hasNoConditions() { + return this.requirementSet.isEmpty(); + } + public void addSatisfiedCondition(UUID player, ICondition c) { synchronized (playerDone) { playerDone.computeIfAbsent(player, k -> new HashSet<>()); @@ -104,7 +108,7 @@ public void clearTradeState(UUID player) { } public boolean isUnlockedPlayer(UUID player) { - return requirementSet.equals(playerDone.get(player)); + return requirementSet.equals(playerDone.getOrDefault(player, new HashSet<>())); } public Set getAllUnlockedPlayers() { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 8dda1bb..5bca5b3 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -23,6 +23,7 @@ public class TradeManager { public static TradeManager INSTANCE = new TradeManager(); private final Map> availableTrades = new HashMap<>(); + private final List noConditionTrades = new ArrayList<>(); public final Map> playerCurrency = new HashMap<>(); @@ -73,8 +74,17 @@ public void setAvailableTrades(UUID player, Set tradeGroups) { public void recomputeAvailableTrades(UUID player) { synchronized (availableTrades) { availableTrades.clear(); + if (player == null) { // only reset no condition trades for entire database reload + noConditionTrades.clear(); + } for (Map.Entry entry : TradeDatabase.INSTANCE.getTradeGroups() .entrySet()) { + if ( + entry.getValue() + .hasNoConditions() + ) { + noConditionTrades.add(entry.getKey()); + } if (player == null) { for (UUID p : entry.getValue() .getAllUnlockedPlayers()) { @@ -97,9 +107,9 @@ public void recomputeAvailableTrades(UUID player) { public List getTrades(UUID player) { long currentTimestamp = System.currentTimeMillis(); synchronized (availableTrades) { - if (!availableTrades.containsKey(player) || availableTrades.get(player) == null) { - return new ArrayList<>(); - } + availableTrades.computeIfAbsent(player, k -> new HashSet<>()); + availableTrades.get(player) + .addAll(noConditionTrades); ArrayList tradeList = new ArrayList<>(); for (UUID tgId : availableTrades.get(player)) { TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); From f6abdad10699bf25deb24db7f17c9bf140e25b5a Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 28 Sep 2025 15:19:40 +0800 Subject: [PATCH 4/7] Swapped structure definition back to newer structurelib definition type --- .../blocks/MTEVendingMachine.java | 171 +++++++++--------- .../blocks/MTEVendingUplinkHatch.java | 35 +++- .../blocks/gui/TradeMainPanel.java | 17 +- .../vendingmachine/util/BigItemStack.java | 12 +- 4 files changed, 138 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 8d1f0dc..2643c91 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -1,12 +1,9 @@ package com.cubefury.vendingmachine.blocks; -import static gregtech.api.casing.Casings.TinItemPipeCasing; +import static gregtech.api.util.GTStructureUtility.ofHatchAdderOptional; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -49,30 +46,35 @@ import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import gregtech.api.GregTechAPI; import gregtech.api.covers.CoverRegistry; import gregtech.api.enums.Textures; -import gregtech.api.interfaces.IHatchElement; import gregtech.api.interfaces.ISecondaryDescribable; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.MTEMultiBlockBase; import gregtech.api.render.TextureFactory; -import gregtech.api.structure.IStructureInstance; -import gregtech.api.structure.IStructureProvider; -import gregtech.api.structure.StructureWrapper; -import gregtech.api.structure.StructureWrapperInstanceInfo; import gregtech.api.util.GTUtil; import gregtech.api.util.GTUtility; -import gregtech.api.util.IGTHatchAdder; import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.blocks.BlockCasings11; public class MTEVendingMachine extends MTEMultiBlockBase - implements ISurvivalConstructable, ISecondaryDescribable, IAlignment, IStructureProvider { - - public static final String[][] STRUCTURE = { { "cc", "c~", "cc" } }; - protected final StructureWrapper structure; - protected final StructureWrapperInstanceInfo structureInstanceInfo; + implements ISurvivalConstructable, ISecondaryDescribable, IAlignment { + + private static final IStructureDefinition STRUCTURE_DEFINITION = IStructureDefinition + .builder() + .addShape("main", new String[][] { { "cc", "c~", "cc" } }) + .addElement( + 'c', + ofHatchAdderOptional( + MTEVendingMachine::addUplinkHatch, + ((BlockCasings11) GregTechAPI.sBlockCasings11).getTextureIndex(0), + 1, + GregTechAPI.sBlockCasings11, + 0)) + .build(); private final ArrayList uplinkHatches = new ArrayList<>(); @@ -110,18 +112,15 @@ public class MTEVendingMachine extends MTEMultiBlockBase public MTEVendingMachine(final int aID, final String aName, final String aNameRegional) { super(aID, aName, aNameRegional); - - this.structure = new StructureWrapper<>(this); - this.structureInstanceInfo = null; - - this.structure.loadStructure(); } - protected MTEVendingMachine(MTEVendingMachine prototype) { - super(prototype.mName); + protected MTEVendingMachine(String aName) { + super(aName); + } - this.structure = prototype.structure; - this.structureInstanceInfo = new StructureWrapperInstanceInfo<>(structure); + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTEVendingMachine(this.mName); } public void sendTradeRequest(TradeItemDisplay trade) { @@ -265,7 +264,8 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } } } - if (requiredAmount > 0) { + requiredStack.stackSize = requiredAmount; + if (requiredAmount > 0 && fetchItemFromAE(requiredStack, false)) { return false; } } @@ -294,6 +294,13 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { return true; } + public boolean fetchItemFromAE(ItemStack requiredStack, boolean simulate) { + // VendingMachine.LOG.info("AE Fetch object {}", this); + // VendingMachine.LOG.info("AE Fetch uplink hatch size: {}", this.uplinkHatches.size()); + return false; + // return this.uplinkHatches.stream().anyMatch(hatch -> hatch.removeItem(requiredStack, simulate)); + } + @Override public boolean getDefaultHasMaintenanceChecks() { return false; @@ -304,6 +311,11 @@ public String[] getStructureDescription(ItemStack stackSize) { return getTooltip().getStructureHint(); } + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + protected MultiblockTooltipBuilder getTooltip() { if (tooltipBuilder == null) { tooltipBuilder = new MultiblockTooltipBuilder(); @@ -440,18 +452,27 @@ public IAlignmentLimits getAlignmentLimits() { return (d, r, f) -> (d.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0; } - @Override - public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { - return new MTEVendingMachine(this); - } - @Override public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { if (getBaseMetaTileEntity() == null) { VendingMachine.LOG.warn("Check machine failed as Base MTE is null"); return false; } - return structure.checkStructure(this); + // VendingMachine.LOG.info("checkmachine: {}", this); + // VendingMachine.LOG.info("checkmachine uplinkhatches {}", this.uplinkHatches.size()); + this.uplinkHatches.clear(); + return STRUCTURE_DEFINITION.check( + this, + "main", + getBaseMetaTileEntity().getWorld(), + getExtendedFacing(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord(), + 1, + 1, + 0, + !mMachine); } @Override @@ -483,12 +504,38 @@ public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { @Override public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { if (mMachine) return -1; - return structure.survivalConstruct(this, stackSize, elementBudget, env); + return STRUCTURE_DEFINITION.survivalBuild( + this, + stackSize, + "main", + getBaseMetaTileEntity().getWorld(), + getExtendedFacing(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord(), + 1, + 1, + 0, + elementBudget, + env, + false); } @Override public void construct(ItemStack stackSize, boolean hintsOnly) { - structure.construct(this, stackSize, hintsOnly); + STRUCTURE_DEFINITION.buildOrHints( + this, + stackSize, + "main", + getBaseMetaTileEntity().getWorld(), + getExtendedFacing(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord(), + 1, + 1, + 0, + hintsOnly); } @Override @@ -558,54 +605,14 @@ public void spawnItem(ItemStack stack) { world.spawnEntityInWorld(itemEntity); } - @Override - public String[][] getDefinition() { - return STRUCTURE; - } - - @Override - public IStructureDefinition compile(String[][] definition) { - structure.addCasing('c', TinItemPipeCasing) - .withHatches(1, 1, Collections.singletonList(VendingUplinkHatchAdder.INSTANCE)); - return structure.buildStructure(definition); - } - - @Override - public IStructureInstance getStructureInstance() { - return this.structureInstanceInfo; - } - - private enum VendingUplinkHatchAdder implements IHatchElement { - - INSTANCE; - - @Override - public List> mteClasses() { - return Arrays.asList(MTEVendingUplinkHatch.class); - } - - @Override - public IGTHatchAdder adder() { - return (vm, hatchTE, aBaseCasingIndex) -> { - if (hatchTE == null || hatchTE.isDead()) return false; - - IMetaTileEntity aMetaTileEntity = hatchTE.getMetaTileEntity(); - - if (aMetaTileEntity == null) return false; - - if (!(aMetaTileEntity instanceof MTEVendingUplinkHatch uplinkHatch)) return false; - - vm.uplinkHatches.add(uplinkHatch); - uplinkHatch.updateTexture(aBaseCasingIndex); - uplinkHatch.updateCraftingIcon(uplinkHatch.getMachineCraftingIcon()); - - return true; - }; - } - - @Override - public long count(MTEVendingMachine mteVendingMachine) { - return mteVendingMachine.uplinkHatches.size(); - } + private boolean addUplinkHatch(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { + if (aBaseMetaTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (!(aMetaTileEntity instanceof MTEVendingUplinkHatch uplinkHatch)) return false; + uplinkHatch.updateTexture(aBaseCasingIndex); + uplinkHatch.updateCraftingIcon(uplinkHatch.getMachineCraftingIcon()); + this.uplinkHatches.add(uplinkHatch); + return true; } } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index aa8a174..323fe67 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -13,22 +13,27 @@ import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.items.VMItems; +import appeng.api.config.Actionable; import appeng.api.implementations.IPowerChannelState; import appeng.api.networking.GridFlags; import appeng.api.networking.IGridNode; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.MachineSource; import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.data.IAEItemStack; import appeng.api.util.AECableType; import appeng.api.util.DimensionalCoord; import appeng.me.GridAccessException; import appeng.me.helpers.AENetworkProxy; import appeng.me.helpers.IGridProxyable; +import appeng.util.item.AEItemStack; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.MTEHatch; import gregtech.api.render.TextureFactory; -public class MTEVendingUplinkHatch extends MTEHatch implements IGridProxyable, IPowerChannelState { +public class MTEVendingUplinkHatch extends MTEHatch implements IGridProxyable, IPowerChannelState, IActionHost { protected AENetworkProxy gridProxy = null; protected boolean additionalConnection = false; @@ -105,6 +110,11 @@ public IGridNode getGridNode(ForgeDirection dir) { return getProxy().getNode(); } + @Override + public IGridNode getActionableNode() { + return getProxy().getNode(); + } + @Override public void securityBreak() {} @@ -152,16 +162,27 @@ public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrench return true; } - public boolean hasItem() { - IStorageGrid storage = null; + private IStorageGrid accessStorage() { try { - storage = getProxy().getStorage(); + return getProxy().getStorage(); } catch (GridAccessException gae) { VendingMachine.LOG.info(gae); gae.printStackTrace(); - return false; } - return storage == null; + return null; + } + + public boolean removeItem(ItemStack remove, boolean simulate) { + if (remove == null) return true; + IStorageGrid storage = accessStorage(); + VendingMachine.LOG.info(storage); + if (storage == null) return false; + IAEItemStack stack = storage.getItemInventory() + .extractItems( + AEItemStack.create(remove), + simulate ? Actionable.SIMULATE : Actionable.MODULATE, + new MachineSource(this)); + VendingMachine.LOG.info(stack); + return stack != null && stack.getStackSize() >= remove.stackSize; } - } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java index adbc310..2bae650 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -142,6 +142,7 @@ public void onUpdate() { ) { updateGui(); MTEVendingMachineGui.resetForceRefresh(); + TradeManager.INSTANCE.hasCurrencyUpdate = false; } this.ticksOpen += 1; } @@ -168,7 +169,7 @@ public ItemStack convertToItemStack(BigItemStack stack) { public boolean checkCurrencySatisfied(List currencyItems, Map availableItems) { - if (currencyItems == null) { + if (currencyItems == null || currencyItems.isEmpty()) { return true; } if (availableItems == null) { @@ -182,7 +183,19 @@ public boolean checkItemsSatisfied(List trade, Map Date: Mon, 29 Sep 2025 20:56:45 +0800 Subject: [PATCH 5/7] Swapped syncing to item displays in preparation for AE compat --- .../blocks/MTEVendingMachine.java | 77 +++++++- .../blocks/gui/InterceptingSlot.java | 4 +- .../blocks/gui/MTEVendingMachineGui.java | 15 +- .../blocks/gui/TradeMainPanel.java | 171 +++--------------- .../integration/betterquesting/BqAdapter.java | 13 -- .../network/PacketTypeRegistry.java | 8 +- .../handlers/NetAvailableTradeSync.java | 76 -------- .../network/handlers/NetBulkSync.java | 1 - ...adeStateSync.java => NetCurrencySync.java} | 55 ++---- .../network/handlers/NetTradeDisplaySync.java | 166 +++++++++++++++++ .../vendingmachine/trade/TradeGroup.java | 18 +- .../trade/TradeGroupWrapper.java | 7 - .../vendingmachine/trade/TradeManager.java | 44 +---- .../vendingmachine/util/BigItemStack.java | 7 + 14 files changed, 319 insertions(+), 343 deletions(-) delete mode 100644 src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java rename src/main/java/com/cubefury/vendingmachine/network/handlers/{NetTradeStateSync.java => NetCurrencySync.java} (62%) create mode 100644 src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java delete mode 100644 src/main/java/com/cubefury/vendingmachine/trade/TradeGroupWrapper.java diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 2643c91..a45d66d 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -4,13 +4,16 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingQueue; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -27,9 +30,9 @@ import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplay; -import com.cubefury.vendingmachine.network.handlers.NetAvailableTradeSync; +import com.cubefury.vendingmachine.network.handlers.NetCurrencySync; +import com.cubefury.vendingmachine.network.handlers.NetTradeDisplaySync; import com.cubefury.vendingmachine.network.handlers.NetTradeRequestSync; -import com.cubefury.vendingmachine.network.handlers.NetTradeStateSync; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; import com.cubefury.vendingmachine.trade.Trade; @@ -107,6 +110,9 @@ public class MTEVendingMachine extends MTEMultiBlockBase public final Queue pendingTrades = new LinkedBlockingQueue<>(); private boolean newBufferedOutputs = false; private int ticksSinceOutput = 0; + private int ticksSinceTradeUpdate = 0; + + private Map inputSlotCache = new HashMap<>(); private EntityPlayer currentUser = null; @@ -290,7 +296,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { TradeDatabase.INSTANCE.getTradeGroups() .get(tradeRequest.tradeGroup) .executeTrade(tradeRequest.playerID); - NetTradeStateSync.sendTradeState(tradeRequest.player, false); + this.sendTradeUpdate(); return true; } @@ -337,10 +343,6 @@ protected boolean forceUseMui2() { @Override protected @NotNull MTEVendingMachineGui getGui() { - if (VendingMachine.proxy.isClient()) { - NetAvailableTradeSync.requestSync(); - NetTradeStateSync.requestSync(); - } return new MTEVendingMachineGui(this); } @@ -482,6 +484,9 @@ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { } if (aBaseMetaTileEntity.isServerSide()) { dispenseItems(); + if (this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { + this.sendTradeUpdate(); + } if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { this.mMachine = checkMachine(aBaseMetaTileEntity, null); aBaseMetaTileEntity.setActive(this.mMachine); @@ -489,6 +494,62 @@ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { } } + public void sendTradeUpdate() { + this.ticksSinceTradeUpdate = 0; + if (this.currentUser == null) { + return; + } + NetCurrencySync.syncCurrencyToClient((EntityPlayerMP) this.currentUser); + NetTradeDisplaySync.syncTradesToClient((EntityPlayerMP) this.currentUser, this); + } + + public void refreshInputSlotCache() { + Map items = new HashMap<>(); + for (int i = 0; i < INPUT_SLOTS; i++) { + ItemStack stack = this.inputItems.getStackInSlot(i); + if (stack != null) { + BigItemStack tmp = new BigItemStack(stack); + tmp.stackSize = 1; + items.putIfAbsent(tmp, 0); + items.replace(tmp, items.get(tmp) + stack.stackSize); + } + } + this.inputSlotCache = items; + } + + public boolean inputItemsSatisfied(List fromItems) { + for (BigItemStack bis : fromItems) { + BigItemStack base = bis.copy(); + base.stackSize = 1; // shouldn't need this, but just in case + + ItemStack aeStackSearch = base.getBaseStack(); + aeStackSearch.stackSize = bis.stackSize; + if (this.inputSlotCache.get(base) != null) { + aeStackSearch.stackSize = Math.max(aeStackSearch.stackSize - this.inputSlotCache.get(base), 0); + } + if (aeStackSearch.stackSize == 0) { + continue; + } + if (!this.fetchItemFromAE(aeStackSearch, true)) { + return false; + } + } + return true; + } + + public boolean inputCurrencySatisfied(List currencyItems, UUID player) { + if (currencyItems == null || currencyItems.isEmpty()) { + return true; + } + Map availableCurrency = TradeManager.INSTANCE.playerCurrency.get(player); + if (availableCurrency == null) { + return false; + } + // TODO: Add AE2 coin item support + return currencyItems.stream() + .allMatch(ci -> availableCurrency.containsKey(ci.type) && availableCurrency.get(ci.type) >= ci.value); + } + public boolean getActive() { return this.getBaseMetaTileEntity() != null && this.getBaseMetaTileEntity() .isActive(); @@ -553,6 +614,8 @@ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlaye } if (canUse(aPlayer)) { this.currentUser = aPlayer; + // force trade state update now + this.ticksSinceTradeUpdate = Config.gui_refresh_interval; openGui(aPlayer); } else { aPlayer.addChatComponentMessage(new ChatComponentTranslation("vendingmachine.gui.error.player_using")); diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java index e040010..582335e 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java @@ -6,7 +6,7 @@ import com.cleanroommc.modularui.utils.item.ItemStackHandler; import com.cleanroommc.modularui.widgets.slot.ModularSlot; -import com.cubefury.vendingmachine.network.handlers.NetTradeStateSync; +import com.cubefury.vendingmachine.network.handlers.NetCurrencySync; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; import com.cubefury.vendingmachine.trade.TradeManager; @@ -24,7 +24,7 @@ public boolean intercept(ItemStack newItem, boolean client, EntityPlayer player) this.putStack(null); if (!client) { TradeManager.INSTANCE.addCurrency(NameCache.INSTANCE.getUUIDFromPlayer(player), mapped); - NetTradeStateSync.sendPlayerCurrency((EntityPlayerMP) player, mapped); + NetCurrencySync.sendPlayerCurrency((EntityPlayerMP) player, mapped); } return true; } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java index 3c48cf9..93d59d9 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -34,7 +34,8 @@ import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.gui.GuiTextures; import com.cubefury.vendingmachine.gui.WidgetThemes; -import com.cubefury.vendingmachine.network.handlers.NetTradeStateSync; +import com.cubefury.vendingmachine.network.handlers.NetCurrencySync; +import com.cubefury.vendingmachine.network.handlers.NetTradeDisplaySync; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; import com.cubefury.vendingmachine.trade.TradeCategory; @@ -211,7 +212,7 @@ private void doEjectCoin(CurrencyItem.CurrencyType type) { base.spawnItem(ejectable); } TradeManager.INSTANCE.resetCurrency(currentUser, type); - NetTradeStateSync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), type); + NetCurrencySync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), type); this.ejectSingleCoin.put(type, false); } @@ -234,7 +235,7 @@ private void doEjectCoins() { } } TradeManager.INSTANCE.resetCurrency(currentUser, null); - NetTradeStateSync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), null); + NetCurrencySync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), null); ejectCoins = false; } @@ -313,10 +314,16 @@ private SlotGroupWidget createInputRow(PanelSyncManager syncManager) { this.getBase() .getCurrentUser()); if (client) { - forceRefresh = true; return; } // server side force refresh + // Not syncing the trades to client on slot change will cause a short refresh delay, but + // might be worth + // for huge AE systems + NetTradeDisplaySync.syncTradesToClient( + (EntityPlayerMP) this.getBase() + .getCurrentUser(), + this.getBase()); if (hasCoin) { this.refreshInputSlots(); } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java index 2bae650..c25667b 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -18,18 +18,11 @@ import com.cleanroommc.modularui.screen.ModularScreen; import com.cleanroommc.modularui.value.sync.PanelSyncManager; import com.cubefury.vendingmachine.Config; -import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.network.handlers.NetResetVMUser; -import com.cubefury.vendingmachine.storage.NameCache; -import com.cubefury.vendingmachine.trade.CurrencyItem; -import com.cubefury.vendingmachine.trade.Trade; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; -import com.cubefury.vendingmachine.trade.TradeGroup; -import com.cubefury.vendingmachine.trade.TradeGroupWrapper; import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.BigItemStack; -import com.cubefury.vendingmachine.util.Translator; import codechicken.nei.SearchField; import codechicken.nei.api.ItemFilter; @@ -70,55 +63,31 @@ public boolean onKeyRelease(char typedChar, int keyCode) { } public void updateGui() { - boolean test = false; - if (test) { - List testTGW = new ArrayList<>(); - for (Map.Entry entry : TradeDatabase.INSTANCE.getTradeGroups() - .entrySet()) { - testTGW.add(new TradeGroupWrapper(entry.getValue(), -1, true)); - } - Map> trades = formatTrades(testTGW); - gui.updateTradeDisplay(trades); - } else if (shiftHeld) { + if (shiftHeld) { this.updateTradeInformation(gui.getTradeDisplayData()); } else { - Map> trades = formatTrades( - TradeManager.INSTANCE.getTrades(NameCache.INSTANCE.getUUIDFromPlayer(syncManager.getPlayer()))); + Map> trades = formatTrades(); gui.updateTradeDisplay(trades); } } private void updateTradeInformation(Map> currentData) { - Map availableItems = this.guiData.isClient() && this.gui.getBase() != null - ? getAvailableItems() - : new HashMap<>(); + Map> tradeMap = new HashMap<>(); + for (TradeItemDisplay tid : TradeManager.INSTANCE.tradeData) { + tradeMap.putIfAbsent(tid.tgID, new HashMap<>()); + tradeMap.get(tid.tgID) + .put(tid.tradeGroupOrder, tid); + } - Map tradeGroups = new HashMap<>(); - TradeManager.INSTANCE.getTrades(NameCache.INSTANCE.getUUIDFromPlayer(syncManager.getPlayer())) - .forEach( - (tg) -> { - tradeGroups.put( - tg.trade() - .getId(), - tg); - }); currentData.forEach((k, v) -> { for (TradeItemDisplay tid : v) { - TradeGroupWrapper cur = tradeGroups.get(tid.tgID); - tid.enabled = cur != null && cur.enabled(); - tid.hasCooldown = cur.cooldown() > 0; - tid.cooldown = cur.cooldown(); - tid.cooldownText = convertCooldownText(cur.cooldown()); - tid.tradeableNow = checkItemsSatisfied( - cur.trade() - .getTrades() - .get(tid.tradeGroupOrder).fromItems, - availableItems) - && checkCurrencySatisfied( - cur.trade() - .getTrades() - .get(tid.tradeGroupOrder).fromCurrency, - TradeManager.INSTANCE.playerCurrency.get(NameCache.INSTANCE.getUUIDFromPlayer(this.player))); + TradeItemDisplay cur = tradeMap.get(tid.tgID) + .get(tid.tradeGroupOrder); + tid.enabled = cur != null && cur.enabled; + tid.hasCooldown = cur.cooldown > 0; + tid.cooldown = cur.cooldown; + tid.cooldownText = cur.cooldownText; + tid.tradeableNow = cur.tradeableNow; } }); } @@ -137,8 +106,7 @@ public void onUpdate() { MTEVendingMachineGui.setForceRefresh(); } if ( - MTEVendingMachineGui.forceRefresh - || (this.ticksOpen % Config.gui_refresh_interval == 0 && player != null && !shiftHeld) + MTEVendingMachineGui.forceRefresh || (this.ticksOpen % Config.gui_refresh_interval == 0 && player != null) ) { updateGui(); MTEVendingMachineGui.resetForceRefresh(); @@ -147,19 +115,6 @@ public void onUpdate() { this.ticksOpen += 1; } - public String convertCooldownText(long cd) { - if (cd < 60) { - return cd + Translator.translate("vendingmachine.gui.cooldown_display.second"); - } - if (cd < 3600) { - return cd / 60 + Translator.translate("vendingmachine.gui.cooldown_display.minute"); - } - if (cd < 86400) { - return cd / 3600 + Translator.translate("vendingmachine.gui.cooldown_display.hour"); - } - return cd / 86400 + Translator.translate("vendingmachine.gui.cooldown_display.day"); // doom.jpg - } - public ItemStack convertToItemStack(BigItemStack stack) { ItemStack display = stack.getCombinedStacks() .get(0); @@ -167,97 +122,17 @@ public ItemStack convertToItemStack(BigItemStack stack) { return display; } - public boolean checkCurrencySatisfied(List currencyItems, - Map availableItems) { - if (currencyItems == null || currencyItems.isEmpty()) { - return true; - } - if (availableItems == null) { - return false; - } - return currencyItems.stream() - .allMatch(ci -> availableItems.containsKey(ci.type) && availableItems.get(ci.type) >= ci.value); - } - - public boolean checkItemsSatisfied(List trade, Map availableItems) { - for (BigItemStack bis : trade) { - BigItemStack base = bis.copy(); - base.stackSize = 1; // shouldn't need this, but just in case - - ItemStack aeStackSearch = base.getBaseStack(); - aeStackSearch.stackSize = bis.stackSize; - if (availableItems.get(base) != null) { - aeStackSearch.stackSize = Math.max(aeStackSearch.stackSize - availableItems.get(base), 0); - } - if (aeStackSearch.stackSize == 0) { - continue; - } - if ( - !gui.getBase() - .fetchItemFromAE(aeStackSearch, true) - ) { - return false; - } - } - return true; - } - - public Map getAvailableItems() { - Map items = new HashMap<>(); - for (int i = 0; i < MTEVendingMachine.INPUT_SLOTS; i++) { - ItemStack stack = this.gui.getBase().inputItems.getStackInSlot(i); - if (stack != null) { - BigItemStack tmp = new BigItemStack(stack); - tmp.stackSize = 1; - items.putIfAbsent(tmp, 0); - items.replace(tmp, items.get(tmp) + stack.stackSize); - } - } - return items; - } - - public Map> formatTrades(List tradeGroups) { - Map availableItems = this.guiData.isClient() && this.gui.getBase() != null - ? getAvailableItems() - : new HashMap<>(); - + public Map> formatTrades() { Map> trades = new HashMap<>(); trades.put(TradeCategory.ALL, new ArrayList<>()); - - for (TradeGroupWrapper tgw : tradeGroups) { - List tradeList = tgw.trade() - .getTrades(); - TradeCategory category = tgw.trade() + for (TradeItemDisplay tid : TradeManager.INSTANCE.tradeData) { + TradeCategory category = TradeDatabase.INSTANCE.getTradeGroupFromId(tid.tgID) .getCategory(); trades.putIfAbsent(category, new ArrayList<>()); - for (int i = 0; i < tradeList.size(); i++) { - Trade trade = tgw.trade() - .getTrades() - .get(i); - BigItemStack displayItem = trade.toItems.get(0); - TradeItemDisplay tid = new TradeItemDisplay( - trade.fromCurrency, - trade.fromItems, - trade.toItems, - convertToItemStack(displayItem == null ? trade.displayItem : displayItem), - tgw.trade() - .getId(), - i, - tgw.trade() - .getLabel(), - tgw.cooldown(), - convertCooldownText(tgw.cooldown()), - tgw.cooldown() > 0, - tgw.enabled(), - checkItemsSatisfied(trade.fromItems, availableItems) && checkCurrencySatisfied( - trade.fromCurrency, - TradeManager.INSTANCE.playerCurrency.get(NameCache.INSTANCE.getUUIDFromPlayer(this.player)))); - - trades.get(category) - .add(tid); - trades.get(TradeCategory.ALL) - .add(tid); - } + trades.get(category) + .add(tid); + trades.get(TradeCategory.ALL) + .add(tid); } String searchString = gui.getSearchBarText(); diff --git a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java index 39e4555..a12091a 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java @@ -8,8 +8,6 @@ import javax.annotation.Nullable; -import com.cubefury.vendingmachine.VendingMachine; -import com.cubefury.vendingmachine.network.handlers.NetAvailableTradeSync; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeGroup; import com.google.common.collect.ImmutableMap; @@ -72,7 +70,6 @@ public void setQuestFinished(UUID player, UUID quest) { playerSatisfiedCache.get(player) .add(quest); } - syncAvailableTradesFromServer(); } public void setQuestUnfinished(UUID player, UUID quest) { @@ -85,7 +82,6 @@ public void setQuestUnfinished(UUID player, UUID quest) { } } } - syncAvailableTradesFromServer(); } public void resetQuests(UUID player) { @@ -97,15 +93,6 @@ public void resetQuests(UUID player) { playerSatisfiedCache.remove(player); } } - syncAvailableTradesFromServer(); - } - - public void syncAvailableTradesFromServer() { - // We have to sync these trades even though the trades are only pulled usually during VM GUI opening, - // cuz someone's teammate might finish the quest - if (VendingMachine.proxy.isClient()) { - NetAvailableTradeSync.requestSync(); - } } public boolean checkPlayerCompletedQuest(UUID player, UUID quest) { diff --git a/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java b/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java index 6876caf..6def7a2 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java +++ b/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java @@ -12,14 +12,14 @@ import com.cubefury.vendingmachine.api.network.IPacketRegistry; import com.cubefury.vendingmachine.api.util.Tuple2; -import com.cubefury.vendingmachine.network.handlers.NetAvailableTradeSync; import com.cubefury.vendingmachine.network.handlers.NetBulkSync; +import com.cubefury.vendingmachine.network.handlers.NetCurrencySync; import com.cubefury.vendingmachine.network.handlers.NetNameSync; import com.cubefury.vendingmachine.network.handlers.NetResetVMUser; import com.cubefury.vendingmachine.network.handlers.NetSatisfiedQuestSync; import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; +import com.cubefury.vendingmachine.network.handlers.NetTradeDisplaySync; import com.cubefury.vendingmachine.network.handlers.NetTradeRequestSync; -import com.cubefury.vendingmachine.network.handlers.NetTradeStateSync; public class PacketTypeRegistry implements IPacketRegistry { @@ -30,8 +30,8 @@ public class PacketTypeRegistry implements IPacketRegistry { public void init() { NetTradeDbSync.registerHandler(); - NetTradeStateSync.registerHandler(); - NetAvailableTradeSync.registerHandler(); + NetCurrencySync.registerHandler(); + NetTradeDisplaySync.registerHandler(); NetTradeRequestSync.registerHandler(); NetSatisfiedQuestSync.registerHandler(); NetNameSync.registerHandler(); diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java deleted file mode 100644 index 455d2d4..0000000 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetAvailableTradeSync.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.cubefury.vendingmachine.network.handlers; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -import javax.annotation.Nullable; - -import net.minecraft.client.Minecraft; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.nbt.NBTTagString; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.common.util.Constants; - -import com.cubefury.vendingmachine.VendingMachine; -import com.cubefury.vendingmachine.api.network.UnserializedPacket; -import com.cubefury.vendingmachine.api.util.Tuple2; -import com.cubefury.vendingmachine.network.PacketSender; -import com.cubefury.vendingmachine.network.PacketTypeRegistry; -import com.cubefury.vendingmachine.storage.NameCache; -import com.cubefury.vendingmachine.trade.TradeManager; - -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; - -public class NetAvailableTradeSync { - - private static final ResourceLocation ID_NAME = new ResourceLocation("vendingmachine:availabletrade_sync"); - - public static void registerHandler() { - PacketTypeRegistry.INSTANCE.registerServerHandler(ID_NAME, NetAvailableTradeSync::onServer); - - if (VendingMachine.proxy.isClient()) { - PacketTypeRegistry.INSTANCE.registerClientHandler(ID_NAME, NetAvailableTradeSync::onClient); - } - } - - public static void sendSync(@Nullable EntityPlayerMP player) { - NBTTagList tradeGroups = new NBTTagList(); - for (UUID available : TradeManager.INSTANCE.getAvailableTrades(NameCache.INSTANCE.getUUIDFromPlayer(player))) { - tradeGroups.appendTag(new NBTTagString(available.toString())); - } - NBTTagCompound payload = new NBTTagCompound(); - payload.setTag("tradeGroups", tradeGroups); - PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); - - } - - @SideOnly(Side.CLIENT) - public static void requestSync() { - PacketSender.INSTANCE.sendToServer(new UnserializedPacket(ID_NAME, new NBTTagCompound())); - } - - public static void onServer(Tuple2 message) { - sendSync(message.second()); - } - - @SideOnly(Side.CLIENT) - public static void onClient(NBTTagCompound message) { - if ( // Don't sync in LAN - will delete other player's data - Minecraft.getMinecraft() - .isIntegratedServerRunning() - ) { - return; - } - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(Minecraft.getMinecraft().thePlayer); - Set tradeGroups = new HashSet<>(); - NBTTagList tradeList = message.getTagList("tradeGroups", Constants.NBT.TAG_STRING); - for (int i = 0; i < tradeList.tagCount(); i++) { - tradeGroups.add(UUID.fromString(tradeList.getStringTagAt(i))); - } - TradeManager.INSTANCE.setAvailableTrades(playerId, tradeGroups); - } -} diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetBulkSync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetBulkSync.java index 26746fa..2a80342 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetBulkSync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetBulkSync.java @@ -52,7 +52,6 @@ public static void sendSync(@Nonnull EntityPlayerMP player) { NetNameSync.sendNames(new EntityPlayerMP[] { player }, new UUID[] { playerId }, null); NetTradeDbSync.sendDatabase(player, false); - NetTradeStateSync.sendTradeState(player, false); } private static void onServer(Tuple2 message) { diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeStateSync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java similarity index 62% rename from src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeStateSync.java rename to src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java index c6cd086..84d8f61 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeStateSync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java @@ -12,50 +12,41 @@ import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.api.network.UnserializedPacket; -import com.cubefury.vendingmachine.api.util.Tuple2; import com.cubefury.vendingmachine.network.PacketSender; import com.cubefury.vendingmachine.network.PacketTypeRegistry; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; -import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.NBTConverter; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -public class NetTradeStateSync { +public class NetCurrencySync { - // We can send tradestate + currency data, or just currency data - // The latter is far more lightweight, and will likely see higher traffic volume - private static final ResourceLocation ID_NAME = new ResourceLocation("vendingmachine:tradestate_sync"); + private static final ResourceLocation ID_NAME = new ResourceLocation("vendingmachine:currency_sync"); public static void registerHandler() { - PacketTypeRegistry.INSTANCE.registerServerHandler(ID_NAME, NetTradeStateSync::onServer); - if (VendingMachine.proxy.isClient()) { - PacketTypeRegistry.INSTANCE.registerClientHandler(ID_NAME, NetTradeStateSync::onClient); + PacketTypeRegistry.INSTANCE.registerClientHandler(ID_NAME, NetCurrencySync::onClient); } } // server side code for sending tradegroup data when player opens gui - public static void sendTradeState(@Nonnull EntityPlayerMP player, boolean merge) { - TradeDatabase db = TradeDatabase.INSTANCE; + public static void syncCurrencyToClient(@Nonnull EntityPlayerMP player) { UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); NBTTagCompound payload = new NBTTagCompound(); - payload.setString("dataType", "tradeState"); - payload.setBoolean("merge", merge); + payload.setString("dataType", "currencySync"); NBTConverter.UuidValueType.PLAYER.writeId(playerId, payload); - - db.writeTradeStateToNBT(new NBTTagCompound(), playerId); + payload.setTag("data", TradeManager.INSTANCE.writeCurrencyToNBT(playerId)); PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); } public static void sendPlayerCurrency(@Nonnull EntityPlayerMP player, CurrencyItem currencyItem) { NBTTagCompound payload = new NBTTagCompound(); - payload.setString("dataType", "currency_add"); + payload.setString("dataType", "currencyAdd"); currencyItem.writeToNBT(payload); PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); @@ -63,31 +54,13 @@ public static void sendPlayerCurrency(@Nonnull EntityPlayerMP player, CurrencyIt public static void resetPlayerCurrency(@Nonnull EntityPlayerMP player, @Nullable CurrencyItem.CurrencyType type) { NBTTagCompound payload = new NBTTagCompound(); - payload.setString("dataType", "currency_reset"); + payload.setString("dataType", "currencyReset"); if (type != null) { payload.setString("type", type.id); } PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); } - @SideOnly(Side.CLIENT) - public static void requestSync() { - NBTTagCompound payload = new NBTTagCompound(); - payload.setString("requestType", "getTradeState"); - - PacketSender.INSTANCE.sendToServer(new UnserializedPacket(ID_NAME, payload)); - } - - public static void onServer(Tuple2 message) { - String requestType = message.first() - .getString("requestType"); - if (requestType.equals("getTradeState")) { - sendTradeState(message.second(), false); - } else { - VendingMachine.LOG.warn("Unknown trade state sync request type received: {}", requestType); - } - } - @SideOnly(Side.CLIENT) public static void onClient(NBTTagCompound message) { // Don't wipe everyone else's data if on LAN, since @@ -102,16 +75,18 @@ public static void onClient(NBTTagCompound message) { String dataType = message.getString("dataType"); UUID player = NBTConverter.UuidValueType.PLAYER.readId(message); switch (dataType) { - case "tradeState" -> { - boolean merge = message.getBoolean("merge"); - TradeDatabase.INSTANCE.populateTradeStateFromNBT(message, player, merge); + case "currencySync" -> { + TradeManager.INSTANCE.populateCurrencyFromNBT( + message.getCompoundTag("data"), + NBTConverter.UuidValueType.PLAYER.readId(message), + false); } - case "currency_add" -> { + case "currencyAdd" -> { CurrencyItem currencyItem = CurrencyItem.fromNBT(message.getCompoundTag("currencyItem")); TradeManager.INSTANCE.addCurrency(player, currencyItem); } - case "currency_reset" -> TradeManager.INSTANCE.resetCurrency( + case "currencyReset" -> TradeManager.INSTANCE.resetCurrency( player, message.hasKey("type") ? CurrencyItem.CurrencyType.getTypeFromId(message.getString("type")) : null); default -> VendingMachine.LOG.warn("Unknown trade state sync data received: {}", dataType); diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java new file mode 100644 index 0000000..8962097 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -0,0 +1,166 @@ +package com.cubefury.vendingmachine.network.handlers; + +import java.util.List; +import java.util.UUID; + +import javax.annotation.Nonnull; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.util.Constants; + +import com.cubefury.vendingmachine.VendingMachine; +import com.cubefury.vendingmachine.api.network.UnserializedPacket; +import com.cubefury.vendingmachine.blocks.MTEVendingMachine; +import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; +import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplay; +import com.cubefury.vendingmachine.network.PacketSender; +import com.cubefury.vendingmachine.network.PacketTypeRegistry; +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.Trade; +import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeGroup; +import com.cubefury.vendingmachine.trade.TradeManager; +import com.cubefury.vendingmachine.util.NBTConverter; +import com.cubefury.vendingmachine.util.Translator; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class NetTradeDisplaySync { + + private static final ResourceLocation ID_NAME = new ResourceLocation("vendingmachine:availabletrade_sync"); + + public static void registerHandler() { + + if (VendingMachine.proxy.isClient()) { + PacketTypeRegistry.INSTANCE.registerClientHandler(ID_NAME, NetTradeDisplaySync::onClient); + } + } + + private static class Tradable { + + public UUID tgID; + public int tradeGroupOrder; + public long cooldown; + public boolean enabled; + public boolean tradableNow; + + public Tradable(UUID tgID, int tradeGroupOrder, long cooldown, boolean enabled, boolean tradableNow) { + this.tgID = tgID; + this.tradeGroupOrder = tradeGroupOrder; + this.cooldown = cooldown; + this.enabled = enabled; + this.tradableNow = tradableNow; + } + + public NBTTagCompound writeToNBT(NBTTagCompound nbt) { + NBTConverter.UuidValueType.TRADEGROUP.writeId(this.tgID, nbt); + nbt.setInteger("order", this.tradeGroupOrder); + nbt.setLong("cooldown", this.cooldown); + nbt.setBoolean("enabled", this.enabled); + nbt.setBoolean("tradableNow", this.tradableNow); + + return nbt; + } + + public static Tradable readFromNBT(NBTTagCompound nbt) { + return new Tradable( + NBTConverter.UuidValueType.TRADEGROUP.readId(nbt), + nbt.getInteger("order"), + nbt.getLong("cooldown"), + nbt.getBoolean("enabled"), + nbt.getBoolean("tradableNow")); + } + + public TradeItemDisplay formatItemDisplay() { + TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(this.tgID); + Trade t = tg.getTrades() + .get(this.tradeGroupOrder); + ItemStack displayItem = t.toItems.get(0) + .convertToItemStack(); + return new TradeItemDisplay( + t.fromCurrency, + t.fromItems, + t.toItems, + t.displayItem == null ? t.displayItem.convertToItemStack() : displayItem, + this.tgID, + this.tradeGroupOrder, + tg.getLabel(), + this.cooldown, + convertCooldownText(this.cooldown), + this.cooldown > 0, + this.enabled, + this.tradableNow); + } + + public static String convertCooldownText(long cd) { + if (cd < 60) { + return cd + Translator.translate("vendingmachine.gui.cooldown_display.second"); + } + if (cd < 3600) { + return cd / 60 + Translator.translate("vendingmachine.gui.cooldown_display.minute"); + } + if (cd < 86400) { + return cd / 3600 + Translator.translate("vendingmachine.gui.cooldown_display.hour"); + } + return cd / 86400 + Translator.translate("vendingmachine.gui.cooldown_display.day"); // doom.jpg + } + } + + public static void syncTradesToClient(@Nonnull EntityPlayerMP player, MTEVendingMachine base) { + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(Minecraft.getMinecraft().thePlayer); + List availableGroups = TradeManager.INSTANCE.getAvailableTradeGroups(playerId); + base.refreshInputSlotCache(); + + long currentTimestamp = System.currentTimeMillis(); + + NBTTagCompound payload = new NBTTagCompound(); + NBTTagList trades = new NBTTagList(); + for (TradeGroup tg : availableGroups) { + long lastTradeTime = tg.getTradeState(playerId).lastTrade; + long tradeCount = tg.getTradeState(playerId).tradeCount; + + long cooldownRemaining; + if (tg.cooldown != -1 && lastTradeTime != -1 && (currentTimestamp - lastTradeTime) / 1000 < tg.cooldown) { + cooldownRemaining = tg.cooldown - (currentTimestamp - lastTradeTime) / 1000; + } else { + cooldownRemaining = -1; + } + boolean enabled = tg.maxTrades == -1 || tradeCount < tg.maxTrades; + + for (int i = 0; i < tg.getTrades() + .size(); i++) { + Trade trade = tg.getTrades() + .get(i); + boolean tradableNow = base.inputItemsSatisfied(trade.fromItems) + && base.inputCurrencySatisfied(trade.fromCurrency, playerId); + trades.appendTag( + new Tradable(tg.getId(), i, cooldownRemaining, enabled, tradableNow) + .writeToNBT(new NBTTagCompound())); + } + payload.setTag("trades", trades); + } + PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); + + } + + @SideOnly(Side.CLIENT) + public static void onClient(NBTTagCompound message) { + // TODO: Load trade view on client + List tradeData = TradeManager.INSTANCE.tradeData; + tradeData.clear(); + + NBTTagList trades = message.getTagList("trades", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < trades.tagCount(); i++) { + tradeData.add( + Tradable.readFromNBT(trades.getCompoundTagAt(i)) + .formatItemDisplay()); + } + MTEVendingMachineGui.setForceRefresh(); + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index d02df8d..1436b1d 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -141,12 +141,24 @@ public void setTradeState(UUID player, TradeHistory history) { } public boolean canExecuteTrade(UUID player) { - List availableTrades = TradeManager.INSTANCE.getTrades(player); - for (TradeGroupWrapper trade : availableTrades) { + List availableTrades = TradeManager.INSTANCE.getAvailableTradeGroups(player); + long currentTimestamp = System.currentTimeMillis(); + long lastTradeTime = this.getTradeState(player).lastTrade; + long tradeCount = this.getTradeState(player).tradeCount; + long cooldownRemaining; + if (this.cooldown != -1 && lastTradeTime != -1 && (currentTimestamp - lastTradeTime) / 1000 < this.cooldown) { + cooldownRemaining = this.cooldown - (currentTimestamp - lastTradeTime) / 1000; + } else { + cooldownRemaining = -1; + } + + boolean enabled = this.maxTrades == -1 || tradeCount < this.maxTrades; + + for (TradeGroup trade : availableTrades) { if (trade == null) { // shouldn't happen continue; } - if (trade.trade().id.equals(this.id) && trade.enabled() && trade.cooldown() < 0) { + if (trade.id.equals(this.id) && enabled && cooldownRemaining < 0) { return true; } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupWrapper.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupWrapper.java deleted file mode 100644 index 935b259..0000000 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupWrapper.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.cubefury.vendingmachine.trade; - -import com.github.bsideup.jabel.Desugar; - -@Desugar -// For wrapping tradegroup information for network/vending machine display -public record TradeGroupWrapper(TradeGroup trade, long cooldown, boolean enabled) {} diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 5bca5b3..d527cd6 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -8,13 +8,12 @@ import java.util.Set; import java.util.UUID; -import javax.annotation.Nonnull; - import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.common.util.Constants; import com.cubefury.vendingmachine.VendingMachine; +import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplay; // This is a cache of available trades, maintained server-side // so we don't have to recompute what trades are available every time we send it @@ -30,6 +29,8 @@ public class TradeManager { // For writeback to file in original format, to prevent data loss private final Map> invalidCurrency = new HashMap<>(); + public final List tradeData = new ArrayList<>(); + public boolean hasCurrencyUpdate = false; private TradeManager() {} @@ -53,24 +54,6 @@ public void removeTradeGroup(UUID player, UUID tg) { } } - public Set getAvailableTrades(@Nonnull UUID player) { - synchronized (availableTrades) { - Set trades = new HashSet<>(); - if (availableTrades.containsKey(player)) { - trades.addAll(availableTrades.get(player)); - } - return trades; - } - } - - public void setAvailableTrades(UUID player, Set tradeGroups) { - synchronized (availableTrades) { - availableTrades.put(player, new HashSet<>()); - availableTrades.get(player) - .addAll(tradeGroups); - } - } - public void recomputeAvailableTrades(UUID player) { synchronized (availableTrades) { availableTrades.clear(); @@ -104,29 +87,14 @@ public void recomputeAvailableTrades(UUID player) { } } - public List getTrades(UUID player) { - long currentTimestamp = System.currentTimeMillis(); + public List getAvailableTradeGroups(UUID player) { synchronized (availableTrades) { availableTrades.computeIfAbsent(player, k -> new HashSet<>()); availableTrades.get(player) .addAll(noConditionTrades); - ArrayList tradeList = new ArrayList<>(); + ArrayList tradeList = new ArrayList<>(); for (UUID tgId : availableTrades.get(player)) { - TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); - long lastTradeTime = tg.getTradeState(player).lastTrade; - long tradeCount = tg.getTradeState(player).tradeCount; - - long cooldownRemaining; - if ( - tg.cooldown != -1 && lastTradeTime != -1 && (currentTimestamp - lastTradeTime) / 1000 < tg.cooldown - ) { - cooldownRemaining = tg.cooldown - (currentTimestamp - lastTradeTime) / 1000; - } else { - cooldownRemaining = -1; - } - - boolean enabled = tg.maxTrades == -1 || tradeCount < tg.maxTrades; - tradeList.add(new TradeGroupWrapper(tg, cooldownRemaining, enabled)); + tradeList.add(TradeDatabase.INSTANCE.getTradeGroupFromId(tgId)); } return tradeList; } diff --git a/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java b/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java index 48ca34c..f0e23ea 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java +++ b/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java @@ -209,6 +209,13 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { return nbt; } + public ItemStack convertToItemStack() { + ItemStack display = this.getCombinedStacks() + .get(0); + display.stackSize = this.stackSize; + return display; + } + @Optional.Method(modid = "betterquesting") public betterquesting.api.utils.BigItemStack toBQBigItemStack() { betterquesting.api.utils.BigItemStack newBis = new betterquesting.api.utils.BigItemStack( From 76924221f0f72bf49e6f4176ea792bdd0a616fe9 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 30 Sep 2025 13:17:31 +0800 Subject: [PATCH 6/7] Added AE2 Item integration --- .../cubefury/vendingmachine/blocks/MTEVendingMachine.java | 8 ++------ .../vendingmachine/blocks/MTEVendingUplinkHatch.java | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index a45d66d..d6e4257 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -301,10 +301,8 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } public boolean fetchItemFromAE(ItemStack requiredStack, boolean simulate) { - // VendingMachine.LOG.info("AE Fetch object {}", this); - // VendingMachine.LOG.info("AE Fetch uplink hatch size: {}", this.uplinkHatches.size()); - return false; - // return this.uplinkHatches.stream().anyMatch(hatch -> hatch.removeItem(requiredStack, simulate)); + return this.uplinkHatches.stream() + .anyMatch(hatch -> hatch.removeItem(requiredStack, simulate)); } @Override @@ -460,8 +458,6 @@ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack a VendingMachine.LOG.warn("Check machine failed as Base MTE is null"); return false; } - // VendingMachine.LOG.info("checkmachine: {}", this); - // VendingMachine.LOG.info("checkmachine uplinkhatches {}", this.uplinkHatches.size()); this.uplinkHatches.clear(); return STRUCTURE_DEFINITION.check( this, diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index 323fe67..5e5f601 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -175,14 +175,12 @@ private IStorageGrid accessStorage() { public boolean removeItem(ItemStack remove, boolean simulate) { if (remove == null) return true; IStorageGrid storage = accessStorage(); - VendingMachine.LOG.info(storage); if (storage == null) return false; IAEItemStack stack = storage.getItemInventory() .extractItems( AEItemStack.create(remove), simulate ? Actionable.SIMULATE : Actionable.MODULATE, new MachineSource(this)); - VendingMachine.LOG.info(stack); return stack != null && stack.getStackSize() >= remove.stackSize; } } From ab9a312a56c6896b16b01177698e9666b6d02331 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 30 Sep 2025 17:00:10 +0800 Subject: [PATCH 7/7] Fixed item claiming becoming broken upon first claim failure. --- .../blocks/MTEVendingMachine.java | 40 +++++++++++++------ .../blocks/MTEVendingUplinkHatch.java | 4 +- .../network/handlers/NetTradeDisplaySync.java | 3 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index d6e4257..e7d6220 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -223,21 +223,31 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { ) { return false; } + this.refreshInputSlotCache(); + + Trade trade = TradeDatabase.INSTANCE.getTradeGroupFromId(tradeRequest.tradeGroup) + .getTrades() + .get(tradeRequest.tradeGroupOrder); + + if ( + !this.inputCurrencySatisfied(trade.fromCurrency, tradeRequest.playerID) + || !this.inputItemsSatisfied(trade.fromItems) + ) { + return false; + } + ItemStack[] inputSlots = new ItemStack[MTEVendingMachine.INPUT_SLOTS]; for (int i = 0; i < MTEVendingMachine.INPUT_SLOTS; i++) { ItemStack curStack = this.inputItems.getStackInSlot(i); inputSlots[i] = curStack == null ? null : curStack.copy(); } - Trade trade = TradeDatabase.INSTANCE.getTradeGroupFromId(tradeRequest.tradeGroup) - .getTrades() - .get(tradeRequest.tradeGroupOrder); - Map coinInventory = TradeManager.INSTANCE.playerCurrency - .get(NameCache.INSTANCE.getUUIDFromPlayer(this.getCurrentUser())); + UUID currentPlayer = NameCache.INSTANCE.getUUIDFromPlayer(this.getCurrentUser()); + + TradeManager.INSTANCE.playerCurrency.putIfAbsent(currentPlayer, new HashMap<>()); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(currentPlayer); + Map newCoinInventory = new HashMap<>(); - if (coinInventory == null) { - return false; - } for (CurrencyItem ci : trade.fromCurrency) { int oldValue = coinInventory.get(ci.type); if (!coinInventory.containsKey(ci.type) || oldValue < ci.value) { @@ -248,7 +258,9 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } for (BigItemStack stack : trade.fromItems) { - ItemStack requiredStack = stack.getBaseStack(); + ItemStack requiredStack = stack.getBaseStack() + .copy(); + requiredStack.stackSize = 1; // just in case it's not pulled as 1 for some reason int requiredAmount = stack.stackSize; // Remove Items from last stacks if possible for (int i = MTEVendingMachine.INPUT_SLOTS - 1; i >= 0 && requiredAmount > 0; i--) { @@ -271,7 +283,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } } requiredStack.stackSize = requiredAmount; - if (requiredAmount > 0 && fetchItemFromAE(requiredStack, false)) { + if (requiredAmount > 0 && !fetchItemFromAE(requiredStack, false)) { return false; } } @@ -301,8 +313,12 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } public boolean fetchItemFromAE(ItemStack requiredStack, boolean simulate) { - return this.uplinkHatches.stream() - .anyMatch(hatch -> hatch.removeItem(requiredStack, simulate)); + for (MTEVendingUplinkHatch hatch : this.uplinkHatches) { + if (hatch.removeItem(requiredStack, simulate)) { + return true; + } + } + return false; } @Override diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index 5e5f601..10e6d6b 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -166,14 +166,14 @@ private IStorageGrid accessStorage() { try { return getProxy().getStorage(); } catch (GridAccessException gae) { - VendingMachine.LOG.info(gae); + VendingMachine.LOG.warn("Could not access storage: ", gae); gae.printStackTrace(); } return null; } public boolean removeItem(ItemStack remove, boolean simulate) { - if (remove == null) return true; + if (remove == null || remove.stackSize <= 0) return true; IStorageGrid storage = accessStorage(); if (storage == null) return false; IAEItemStack stack = storage.getItemInventory() diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java index 8962097..a399f08 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -5,7 +5,6 @@ import javax.annotation.Nonnull; -import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -113,7 +112,7 @@ public static String convertCooldownText(long cd) { } public static void syncTradesToClient(@Nonnull EntityPlayerMP player, MTEVendingMachine base) { - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(Minecraft.getMinecraft().thePlayer); + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); List availableGroups = TradeManager.INSTANCE.getAvailableTradeGroups(playerId); base.refreshInputSlotCache();