From 78f6909ff08e269a9d325d8777729b5d835ba0af Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Tue, 7 Oct 2025 10:08:56 +0200 Subject: [PATCH 001/160] update --- dependencies.gradle | 16 ++++++++-------- settings.gradle.kts | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index d4a2fbb..625bcb8 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.7.77-GTNH:dev") - implementation("com.github.GTNewHorizons:GTNHLib:0.6.39:dev") - compileOnly("com.github.GTNewHorizons:BetterQuesting:3.7.11-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.2.18-1.7.10:dev") - // implementation("com.github.GTNewHorizons:ModularUI2:99.99:dev") - implementation("com.github.GTNewHorizons:StructureLib:1.4.18:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.440:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.6-GTNH:dev") + implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") + compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.4-GTNH:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") + // implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") + implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.19:dev") } // deps may transitively add Baubles, so we replace it @@ -49,7 +49,7 @@ project.getConfigurations() final DependencySubstitutions ds = c.getResolutionStrategy() .getDependencySubstitution() ds.substitute(ds.module("com.github.GTNewHorizons:Baubles")) - .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.1.9-GTNH")) + .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.2.0-GTNH")) .withClassifier("dev") .because("Baubles-Expanded replaces Baubles") }) diff --git a/settings.gradle.kts b/settings.gradle.kts index cbf0d00..0966c6f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,5 +17,5 @@ pluginManagement { } plugins { - id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.41") + id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.43") } From ee6c746eed123cf52d213094a9f33b6d0193b4b1 Mon Sep 17 00:00:00 2001 From: Ranzu <66495944+Ranzuu@users.noreply.github.com> Date: Tue, 7 Oct 2025 15:54:02 +0200 Subject: [PATCH 002/160] pixels --- .../vendingmachine/textures/gui/tabs_left.png | Bin 3140 -> 3188 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/vendingmachine/textures/gui/tabs_left.png b/src/main/resources/assets/vendingmachine/textures/gui/tabs_left.png index 0c532c63b880212a322cf41a264edf3881e04bc5..9e5b665373066bd798a762a156320dd830c46589 100644 GIT binary patch literal 3188 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 DUC74X literal 3140 zcmXw*c|6qH8^^!M*s^a;WXm$jSSF1vWf=^TeP0@l^@f=kS;x-UuPu>1JJ+@E5!thh zJriZA5LrS@L-kYl^*iVFeBRIboadb9{CVPx?&&ZyUS1t`h<&@xX=y@doAmj2f{me{BJOpBw zLYGk*TYSdkLpKv@By$%sRr;D71Djq?3LpYUm|+pdsb%yq$VynTW@^1id^DAD{q_Yg zV)hZ1i!W2xsRq3KB4BSkXIbzh|&7>*XqVVY*KDC-IJ?1s#S+Mng5ojlHThzi{WBLvBP$Ce@4%s^e4b2EuT@O0+} z?6;|mI)4zxQ8GY$L$@yr{*gdOu!Bkenw0DH>ZK(+eX4?ok}{inlmeDe&HKSblkRtW zpB()U(-qTja+(ebUM_)Ui2mV;HSG6`>jea|Al*-20Uq`<(e7B83@yZH*)u$8)|tWKue8gOO0=nhO_5FOAmV+z`8<1 ztqzI3@CYTh62X;1g%IN93TrOBlo3&blBfXr7P8An!m*cd;pi24MLOy5QPhPcDic|j z{4mLV#xXUvsOVufZW97dNOPFKA=)a1?;{PZCc6=T2ECZ329lavZM)E3 zb`yfT+yO9awiX(@aZtDe>8{E$l=a%wv3t-qq6`)3lcRWhNA_Wgg3=MKJx{PS!EC!x zhJ8<0*sU1vgqO32v9T*ZPmpEjd8Mt9>MzQ`E?k|$Q9|vm_BKVJM6f*`nOZ(<%LUTX zk~6xS!Sq^?J9_PTW|2h^ytvAk&M2?q_N@6V;~EopN~&XYyvnbWpG}Cw67^^fvA|8_j{fOp*k z54je`AhsZmAX=4VeB{+N9JWRAzTK^RvDf>}S8T8nSW7Ht8~6psd$zqq)`7$Q(XY;A z?O@gr`a8)5!Vu0xhJT}w8rK}5MQM}Tiu!H({_3I}-(v6eW1ok$#aQXyLfkUs7wZ-? zM!JZ?CBsF9J%x89@fJX0x z1KLkITv7wEYnrRZ@sLx9D+Fy8Rb}XG+CJ+$tG#8trO2##ql|Xa#J#i$;}+Q@$sHe` zr`M#Hub1@t5x3-(BEBh_&Cf?LiX+9BqGAp;H#G0w5}$+5U9YO0TdxSH_&TRI`*u!y z_I>4zS^VtGY-^=o z!#|ljKRtgi^Ln~!TDka}SjPA6s%pQQQqTR=+`iV8}B>=Nf+Ub3i@)@ za(pnt_?0o*_0Dkubdu*Dk46G0f$uKIOnP>ohjX&cG&B;*1nrb6um)QV*m^c@wNl(X zF?n9^-0(v&4>;XS-Dc2-)iv4BH!Xw5Z|x53mfNd09ux6iu3kf}i)g=@{J#VryzK3M z^D{ECIC8jX+;MuUM{cTq{wpY9kP+?alIN$P5};J`Sb6#Qm>1xh}JGI6F+;u6~-b_!^bI|hs+yH8-CFdlVOuPMJKNk`!b{P zg2@c5OtlQ5mmE2b*`{8Gb)ZHfGHGi?xt(8SSnSZT9B;ssXKcc|__UuEZY5JkKg7OJ6-#cFxgK8%o7>r6B;16FqgxmDm zPuUjQ*0rE;r5mp)=95*W)q$4VwbC}K-Gi9%@aCvy_lKd7CTS^|;C5*jd&5+Vsb|mY zzlChuCUD1V4Jg3dJSrAr-$E7?+uV1{stg46{l$3oYxJ+{Eo0Wby2($*EuY-SzfEg$ zt{W@zAX;wjZbDXHe%FY;}q60qRxn=(2z4%)3F4YD{_S zQvqs%C_x}JhrIKxPn{6-cU^K5-j!_cN!MIl!ntMlUTN;hwAfDaw!rPn{!OhzrR5)j zM)ytxXH+eG>^}LE7+%Fa=PbClUXXkHiSO3u&mU*dUHXB0xpAsKH8L+S`yP{|!;N5K z-sh7qcLLsjJF91!;7xXLvj5WY5nJig6H@qr?o?12bOoeB;3ss*sMzm<^A&>E;!mH< zSa#Lsck*C&riaf`SGSGdVBRC!gu6yMzi(PlYBpMZyogKIKD_wWkNMMG@u$yD_(J4= z)Z1?fsovgFRo+MSMyjBf>Lur6XGk0`A#=xp?0=>^pPpSl zaOe6jyVJ3cB)^ybXE0fAm7729j?QLkbM9BXT=+G;>%50sIQn4;u61#E`ocKWX9c?L z`KvR_kMl;1#~buLpzsHk(bba%;$^$) zey|Ww8Tb^ie^Yv)#q*RKmA{d(RLw-yAmBh@F*;opJAc^kVU_R)Na{Zjg0lVQN-ChA z4KqlmbQ?1956LajHu#(XbJ~=MkWq9e%gWDD;^V1x>dWqOM5g`$Tvd z_KX(S2lr>_fsbi_}G+&12+!BbDGzB~FY2{Hp5BI14TRSeNrT2jf c`SETSupVERbz7BT;P*jYt$T=nHBb@%1D;gDL;wH) From 32e7bd24f56b9917072c4dcda45ecf21510b3c7b Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 7 Oct 2025 22:06:45 +0800 Subject: [PATCH 003/160] Fixed structurelib display and added hint for uplink hatch in tooltip --- .../blocks/MTEVendingMachine.java | 17 +++++++++++------ .../blocks/gui/MTEVendingMachineGui.java | 17 +++++++++++------ .../assets/vendingmachine/lang/en_US.lang | 1 + 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 54df808..a149496 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -5,6 +5,8 @@ import static com.cubefury.vendingmachine.api.enums.Textures.VM_MACHINE_FRONT_ON_GLOW; import static com.cubefury.vendingmachine.api.enums.Textures.VM_OVERLAY; import static com.cubefury.vendingmachine.api.enums.Textures.VM_OVERLAY_ACTIVE; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; import static gregtech.api.util.GTStructureUtility.ofHatchAdderOptional; import java.util.ArrayList; @@ -79,12 +81,14 @@ public class MTEVendingMachine extends MTEMultiBlockBase .addShape("main", new String[][] { { "cc", "c~", "cc" } }) .addElement( 'c', - ofHatchAdderOptional( - MTEVendingMachine::addUplinkHatch, - ((BlockCasings11) GregTechAPI.sBlockCasings11).getTextureIndex(0), - 1, - GregTechAPI.sBlockCasings11, - 0)) + ofChain( + ofBlock(GregTechAPI.sBlockCasings11, 0), + ofHatchAdderOptional( + MTEVendingMachine::addUplinkHatch, + ((BlockCasings11) GregTechAPI.sBlockCasings11).getTextureIndex(0), + 1, + GregTechAPI.sBlockCasings11, + 0))) .build(); private final ArrayList uplinkHatches = new ArrayList<>(); @@ -359,6 +363,7 @@ protected MultiblockTooltipBuilder getTooltip() { .beginStructureBlock(2, 3, 1, false) .addController("Middle") .addOtherStructurePart("Tin Item Pipe Casings", "Everything except the controller") + .addOtherStructurePart("ME Vending Uplink Hatch", "Any Pipe Casing, Optional") .addStructureInfo("Cannot be flipped onto its side") .toolTipFinisher(); } 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 5fcfd38..47e9bdc 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -128,7 +128,7 @@ public ModularPanel build(PosGuiData guiData, PanelSyncManager syncManager, UISe panel.child( new Column().size(20) .right(5)); - panel.child(createIOColumn(syncManager)); + panel.child(createIOColumn()); return panel; } @@ -253,7 +253,7 @@ private void doEjectItems() { ejectItems = false; } - private IWidget createIOColumn(PanelSyncManager syncManager) { + private IWidget createIOColumn() { return new ParentWidget<>().excludeAreaInNEI() .width(50) .height(178) @@ -336,10 +336,14 @@ private SlotGroupWidget createOutputSlots() { return SlotGroupWidget.builder() .matrix("II", "II", "II") .key('I', index -> { - ModularSlot ms = new ModularSlot(base.outputItems, index).accessibility(false, true) - .slotGroup("outputSlotGroup"); - ms.changeListener((newItem, onlyAmountChanged, client, init) -> {}); - return new ItemSlot().slot(ms); + /* + * ModularSlot ms = new ModularSlot(base.outputItems, index).accessibility(false, true) + * .slotGroup("outputSlotGroup"); + */ + // ms.changeListener((newItem, onlyAmountChanged, client, init) -> {}); + return new ItemSlot().slot( + new ModularSlot(base.outputItems, index).accessibility(false, true) + .slotGroup("outputSlotGroup")); }) .build(); } @@ -388,6 +392,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t builder.emptyLine(); builder.addLine(IKey.str(cur.label).style(IKey.GRAY)); + builder.addLine(IKey.str(Translator.translate("vendingmachine.gui.trade_hint")).style(IKey.GRAY)); } } } diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 70de284..58623e3 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -14,6 +14,7 @@ vendingmachine.gui.coin_eject=Eject All Coins vendingmachine.gui.single_coin_type_eject_hint=Shift-Click to Extract vendingmachine.gui.search=Search vendingmachine.gui.required_inputs=Requires: +vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.cooldown_display.second=s vendingmachine.gui.cooldown_display.minute=m From 04a55e5a721e0f3570f1cc5e97a222ab638476be Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 7 Oct 2025 23:31:47 +0800 Subject: [PATCH 004/160] Cleaned up input/output slot method naming --- .../blocks/gui/MTEVendingMachineGui.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) 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 47e9bdc..f2d80ad 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -268,7 +268,7 @@ private IWidget createIOColumn() { .width(30) .height(20)) .child( - new Row().child(createInputRow().center()) + new Row().child(createInputSlots().center()) .top(20) .height(18 * 3)) .child( @@ -299,7 +299,7 @@ private IWidget createIOColumn() { .right(1)); } - private SlotGroupWidget createInputRow() { + private SlotGroupWidget createInputSlots() { return SlotGroupWidget.builder() .matrix("II", "II", "II") .key('I', index -> { @@ -336,11 +336,6 @@ private SlotGroupWidget createOutputSlots() { return SlotGroupWidget.builder() .matrix("II", "II", "II") .key('I', index -> { - /* - * ModularSlot ms = new ModularSlot(base.outputItems, index).accessibility(false, true) - * .slotGroup("outputSlotGroup"); - */ - // ms.changeListener((newItem, onlyAmountChanged, client, init) -> {}); return new ItemSlot().slot( new ModularSlot(base.outputItems, index).accessibility(false, true) .slotGroup("outputSlotGroup")); @@ -493,8 +488,8 @@ private IWidget createInventoryRow() { @Override protected void registerSyncValues(PanelSyncManager syncManager) { super.registerSyncValues(syncManager); - syncManager.registerSlotGroup("inputSlotGroup", 6, true); - syncManager.registerSlotGroup("outputSlotGroup", 4, false); + syncManager.registerSlotGroup("inputSlotGroup", 2, true); + syncManager.registerSlotGroup("outputSlotGroup", 2, false); BooleanSyncValue ejectItemsSyncer = new BooleanSyncValue(() -> this.ejectItems, val -> { this.ejectItems = val; From 9a52adde08abd574b22353a41e2b17d80b469f16 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 8 Oct 2025 00:17:07 +0800 Subject: [PATCH 005/160] Fixed structure hint. --- .../cubefury/vendingmachine/blocks/MTEVendingMachine.java | 7 ++++--- src/main/resources/assets/vendingmachine/lang/en_US.lang | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index a149496..41cdc09 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -48,6 +48,7 @@ import com.cubefury.vendingmachine.trade.TradeRequest; import com.cubefury.vendingmachine.util.BigItemStack; import com.cubefury.vendingmachine.util.OverlayHelper; +import com.cubefury.vendingmachine.util.Translator; import com.gtnewhorizon.structurelib.StructureLibAPI; import com.gtnewhorizon.structurelib.alignment.IAlignment; import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; @@ -82,13 +83,13 @@ public class MTEVendingMachine extends MTEMultiBlockBase .addElement( 'c', ofChain( - ofBlock(GregTechAPI.sBlockCasings11, 0), ofHatchAdderOptional( MTEVendingMachine::addUplinkHatch, ((BlockCasings11) GregTechAPI.sBlockCasings11).getTextureIndex(0), 1, GregTechAPI.sBlockCasings11, - 0))) + 0), + ofBlock(GregTechAPI.sBlockCasings11, 0))) .build(); private final ArrayList uplinkHatches = new ArrayList<>(); @@ -347,7 +348,7 @@ public boolean getDefaultHasMaintenanceChecks() { @Override public String[] getStructureDescription(ItemStack stackSize) { - return getTooltip().getStructureHint(); + return new String[] { Translator.translate("structure.vendingmachine.hint.1") }; } @Override diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 58623e3..9446c0b 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -2,6 +2,8 @@ item.vendingmachine.placeholder.name=Placeholder Item tooltip.vendingmachine=Who's even restocking this... +structure.vendingmachine.hint.1=Hint 1 Dot: Tin Item Pipe Casing, ME Vending Uplink Hatch + vendingmachine.gui.requirementHeader=Requirements: vendingmachine.gui.requirement.unknown=Unknown Requirement vendingmachine.gui.requirement.betterquesting=Quest From 9a7af7d0ade6a6760b5b43ae06ce18333f5adfa0 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 8 Oct 2025 00:45:08 +0800 Subject: [PATCH 006/160] Fix edge-case NPE on load when player attempts to load tradestate for a removed tradegroup. --- .../java/com/cubefury/vendingmachine/trade/TradeDatabase.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index a6e669a..4d16562 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -126,7 +126,9 @@ public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean m UUID tgId = NBTConverter.UuidValueType.TRADEGROUP.readId(state); TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); TradeHistory th = new TradeHistory(state.getLong("lastTrade"), state.getInteger("tradeCount")); - tg.setTradeState(player, th); + if (tg != null) { + tg.setTradeState(player, th); + } } TradeManager.INSTANCE.populateCurrencyFromNBT(nbt, player, merge); } From d7ab8bb5cb7634337e7cb5046f74006afca7c250 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Wed, 8 Oct 2025 08:33:00 +0200 Subject: [PATCH 007/160] update --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 625bcb8..9bd54c8 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -36,11 +36,11 @@ dependencies { implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.6-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") - compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.4-GTNH:dev") + compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") // implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.19:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.21:dev") } // deps may transitively add Baubles, so we replace it From e0646fb6c545568c0a7e87bd15e67b8f94b14879 Mon Sep 17 00:00:00 2001 From: Omgise <106000018+Omgise@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:44:57 +0800 Subject: [PATCH 008/160] Update zh_CN.lang --- .../assets/vendingmachine/lang/zh_CN.lang | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/resources/assets/vendingmachine/lang/zh_CN.lang b/src/main/resources/assets/vendingmachine/lang/zh_CN.lang index 2893c68..070ba55 100644 --- a/src/main/resources/assets/vendingmachine/lang/zh_CN.lang +++ b/src/main/resources/assets/vendingmachine/lang/zh_CN.lang @@ -2,6 +2,8 @@ item.vendingmachine.placeholder.name=占位符物品 tooltip.vendingmachine=到底是谁在补货啊... +structure.vendingmachine.hint.1=Hint 1 Dot: Tin Item Pipe Casing, ME Vending Uplink Hatch + vendingmachine.gui.requirementHeader=需求条件: vendingmachine.gui.requirement.unknown=未知需求 vendingmachine.gui.requirement.betterquesting=任务 @@ -10,15 +12,21 @@ vendingmachine.gui.neiColor.conditionDefault=000000 vendingmachine.gui.neiColor.conditionSatisfied=55D441 vendingmachine.gui.neiColor.conditionUnsatisfied=A87A5E vendingmachine.gui.item_eject=取出物品 +vendingmachine.gui.coin_eject=取出所有代币 +vendingmachine.gui.single_coin_type_eject_hint=Shift-点击提取 vendingmachine.gui.search=搜索 vendingmachine.gui.required_inputs=需要: +vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.cooldown_display.second=秒 vendingmachine.gui.cooldown_display.minute=分 vendingmachine.gui.cooldown_display.hour=时 vendingmachine.gui.cooldown_display.day=天 +vendingmachine.gui.error.player_using=当前有其他玩家正在使用此自动售货机 + gt.blockmachines.multimachine.vendingmachine.name=自动售货机 +hatch.vendinguplink.me.name=ME自动售货接入接口 vendingmachine.category.unknown=未知分类 vendingmachine.category.all=全部物品 @@ -29,3 +37,18 @@ vendingmachine.category.chemistry=化工 vendingmachine.category.magic=魔法 vendingmachine.category.bees=蜜蜂 vendingmachine.category.misc=杂项 + +vendingmachine.coin.adventure=探险家代币 +vendingmachine.coin.bees=养蜂员代币 +vendingmachine.coin.blood=吸血鬼代币 +vendingmachine.coin.chemist=化学家代币 +vendingmachine.coin.cook=厨师代币 +vendingmachine.coin.darkWizard=魔法师代币 +vendingmachine.coin.farmer=农民代币 +vendingmachine.coin.flower=园艺代币 +vendingmachine.coin.forestry=护林员代币 +vendingmachine.coin.smith=匠师代币 +vendingmachine.coin.space=太空代币 +vendingmachine.coin.survivor=幸存者代币 +vendingmachine.coin.technician=技术员代币 +vendingmachine.coin.witch=巫师代币 From e1f86c51dd68d5501453099392488a2c6c832df8 Mon Sep 17 00:00:00 2001 From: Omgise <106000018+Omgise@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:50:01 +0800 Subject: [PATCH 009/160] Update zh_CN.lang --- src/main/resources/assets/vendingmachine/lang/zh_CN.lang | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/vendingmachine/lang/zh_CN.lang b/src/main/resources/assets/vendingmachine/lang/zh_CN.lang index 070ba55..dbbc6ac 100644 --- a/src/main/resources/assets/vendingmachine/lang/zh_CN.lang +++ b/src/main/resources/assets/vendingmachine/lang/zh_CN.lang @@ -2,7 +2,7 @@ item.vendingmachine.placeholder.name=占位符物品 tooltip.vendingmachine=到底是谁在补货啊... -structure.vendingmachine.hint.1=Hint 1 Dot: Tin Item Pipe Casing, ME Vending Uplink Hatch +structure.vendingmachine.hint.1=提示 1:锡质物品管道外壳,ME自动售货接入接口 vendingmachine.gui.requirementHeader=需求条件: vendingmachine.gui.requirement.unknown=未知需求 @@ -16,7 +16,7 @@ vendingmachine.gui.coin_eject=取出所有代币 vendingmachine.gui.single_coin_type_eject_hint=Shift-点击提取 vendingmachine.gui.search=搜索 vendingmachine.gui.required_inputs=需要: -vendingmachine.gui.trade_hint=Shift-Click to Purchase +vendingmachine.gui.trade_hint=Shift-点击购买 vendingmachine.gui.cooldown_display.second=秒 vendingmachine.gui.cooldown_display.minute=分 From 8f27d4cc60596f807f93d112d8bc34fddaf031fb Mon Sep 17 00:00:00 2001 From: Ranzu <66495944+Ranzuu@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:54:52 +0200 Subject: [PATCH 010/160] Separate Tile name and gui title --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 6 +++++- src/main/resources/assets/vendingmachine/lang/en_US.lang | 1 + src/main/resources/assets/vendingmachine/lang/zh_CN.lang | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) 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 f2d80ad..e3a7b50 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -118,7 +118,11 @@ public ModularPanel build(PosGuiData guiData, PanelSyncManager syncManager, UISe panel.child(createCategoryTabs(this.tabController)); Flow mainColumn = new Column().width(170); if (VendingMachine.proxy.isClient()) { // client side filtering - mainColumn.child(createTitleTextStyle(base.getLocalName())) + mainColumn.child( + createTitleTextStyle( + IKey.lang("gt.blockmachines.multimachine.vendingmachine.name.gui") + .style(IKey.DARK_GRAY) + .get())) .child(this.searchBar) .child(createTradeUI((TradeMainPanel) panel, this.tabController)); mainColumn.child(createCoinInventoryRow((TradeMainPanel) panel)); diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 9446c0b..0583853 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -26,6 +26,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 +gt.blockmachines.multimachine.vendingmachine.name.gui=Vending Machine hatch.vendinguplink.me.name=ME Vending Uplink Hatch vendingmachine.category.unknown=Unknown Category diff --git a/src/main/resources/assets/vendingmachine/lang/zh_CN.lang b/src/main/resources/assets/vendingmachine/lang/zh_CN.lang index dbbc6ac..40f3eea 100644 --- a/src/main/resources/assets/vendingmachine/lang/zh_CN.lang +++ b/src/main/resources/assets/vendingmachine/lang/zh_CN.lang @@ -26,6 +26,7 @@ vendingmachine.gui.cooldown_display.day=天 vendingmachine.gui.error.player_using=当前有其他玩家正在使用此自动售货机 gt.blockmachines.multimachine.vendingmachine.name=自动售货机 +gt.blockmachines.multimachine.vendingmachine.name.gui=自动售货机 hatch.vendinguplink.me.name=ME自动售货接入接口 vendingmachine.category.unknown=未知分类 From d286e856c0dab1cd77ec92651702eb6d72ae2e96 Mon Sep 17 00:00:00 2001 From: Ranzu <66495944+Ranzuu@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:29:48 +0200 Subject: [PATCH 011/160] Localize the ME Vending Uplink Hatch Overlay --- .../vendingmachine/api/enums/Textures.java | 5 ++++- .../blocks/MTEVendingUplinkHatch.java | 8 ++++---- .../vending_uplink_machine_overlay_active.png | Bin 0 -> 426 bytes .../vending_uplink_machine_overlay_inactive.png | Bin 0 -> 429 bytes 4 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_active.png create mode 100644 src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_inactive.png diff --git a/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java b/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java index 13af61d..59354b4 100644 --- a/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java +++ b/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java @@ -18,7 +18,10 @@ public class Textures { VM_OVERLAY_ACTIVE_0 = new CustomIcon("vendingmachine:vending_machine_overlay_active_0"), VM_OVERLAY_ACTIVE_1 = new CustomIcon("vendingmachine:vending_machine_overlay_active_1"), VM_OVERLAY_ACTIVE_2 = new CustomIcon("vendingmachine:vending_machine_overlay_active_2"), - VM_OVERLAY_ACTIVE_3 = new CustomIcon("vendingmachine:vending_machine_overlay_active_3"); + VM_OVERLAY_ACTIVE_3 = new CustomIcon("vendingmachine:vending_machine_overlay_active_3"), + + VUPLINK_OVERLAY_0 = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_inactive"), + VUPLINK_OVERLAY_1 = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_active"); public static final IIconContainer[] VM_OVERLAY_ACTIVE = { VM_OVERLAY_ACTIVE_0, VM_OVERLAY_ACTIVE_1, VM_OVERLAY_ACTIVE_2, VM_OVERLAY_ACTIVE_3, VM_OVERLAY_4 // bottom right not animated diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index 10e6d6b..d190276 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -1,7 +1,7 @@ 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 static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_0; +import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_1; import java.util.EnumSet; @@ -120,12 +120,12 @@ public void securityBreak() {} @Override public ITexture[] getTexturesActive(ITexture aBaseTexture) { - return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_FLUID_HATCH_ACTIVE) }; + return new ITexture[] { aBaseTexture, TextureFactory.of(VUPLINK_OVERLAY_1) }; } @Override public ITexture[] getTexturesInactive(ITexture aBaseTexture) { - return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_FLUID_HATCH) }; + return new ITexture[] { aBaseTexture, TextureFactory.of(VUPLINK_OVERLAY_0) }; } @Override diff --git a/src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_active.png b/src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_active.png new file mode 100644 index 0000000000000000000000000000000000000000..358ce0b7992ef1d0370b35d2795e4adb0933ccee GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|>0G|+72L}gU$3-bADL{ck%Ukb*)RhGJ1^@s5pTR+Ezyvgx39K^6(gMhW>M}Gi0Lf}A zepk0~Vh1TU^mK6y(FjgXaAUr~A~AtMkI_xTfy1DYv5wJA;Fxy9LRMb}t_MsU4Y3TO d3pfponHioNS%G~10G|+72M320D^{eWr0_Z}0*XD_)N=_)v6ck+1^)*EhTq%xKn8IZctjR6 zFz_7$VMb96uLhu?M2TxeNpOBzNqJ&XDnmeGW?qS&pKFMMsh**pWlr8LJD{3vsS%!O zo}O9^96$~$gA^kx10#^-1;o-&Hpt}~jLcwhCLr68kqPXRC?GqtodqnO1!RN3r!q!{ z7eEifXf#V1fKn6K8CZZS4UCKp7#BcH1=+~D0AkVNZa7AjJlrE{-7@!O01Z%r{shCNStRx@kCY7&J20F{Y(CF-b&SU|GPR*T8Ut gHGpvz12;E=T0E0x;OV literal 0 HcmV?d00001 From 3f80365152835e6abd304ec85eff34fa451a0ae9 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 10 Oct 2025 01:49:37 +0800 Subject: [PATCH 012/160] Now sorts by tradegroup id before writing to file, and does not add indices for NBT arrays. This change ensures that changelogs won't be massive every time a new trade is added, from all the tradegroups and their indices getting shuffled around. --- .../vendingmachine/trade/TradeDatabase.java | 7 +-- .../vendingmachine/util/NBTConverter.java | 45 +++++-------------- 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 4d16562..f1db10f 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -109,9 +109,10 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge) { public NBTTagCompound writeToNBT(NBTTagCompound nbt) { nbt.setInteger("version", this.version); NBTTagList tgList = new NBTTagList(); - for (TradeGroup tg : tradeGroups.values()) { - tgList.appendTag(tg.writeToNBT(new NBTTagCompound())); - } + tradeGroups.values() + .stream() + .sorted(Comparator.comparing(TradeGroup::getId)) + .forEach(tg -> tgList.appendTag(tg.writeToNBT(new NBTTagCompound()))); nbt.setTag("tradeGroups", tgList); return nbt; } diff --git a/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java b/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java index 5daf73f..d09ef91 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java +++ b/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java @@ -176,20 +176,11 @@ else if (value instanceof NBTTagByteArray) { out.endArray(); } else if (value instanceof NBTTagList) { List tagList = getTagList((NBTTagList) value); - if (format) { - out.beginObject(); - for (int i = 0; i < tagList.size(); i++) { - NBTBase tag = tagList.get(i); - out.name(i + ":" + tag.getId()); - NBTtoJSON_Base(tag, true, out); - } - out.endObject(); - } else { - out.beginArray(); - for (NBTBase tag : tagList) { - NBTtoJSON_Base(tag, false, out); - } + out.beginArray(); + for (NBTBase tag : tagList) { + NBTtoJSON_Base(tag, format, out); } + out.endArray(); } else if (value instanceof NBTTagCompound) { NBTtoJSON_Compound((NBTTagCompound) value, out, format); } else { @@ -233,31 +224,15 @@ private static JsonElement NBTtoJSON_Base(NBTBase tag, boolean format) { } else if (tag instanceof NBTTagCompound) { return NBTtoJSON_Compound((NBTTagCompound) tag, new JsonObject(), format); } else if (tag instanceof NBTTagList) { - if (format) { - JsonObject jAry = new JsonObject(); - - List tagList = getTagList((NBTTagList) tag); - - for (int i = 0; i < tagList.size(); i++) { - jAry.add( - i + ":" - + tagList.get(i) - .getId(), - NBTtoJSON_Base(tagList.get(i), true)); - } - - return jAry; - } else { - JsonArray jAry = new JsonArray(); - - List tagList = getTagList((NBTTagList) tag); + JsonArray jAry = new JsonArray(); - for (NBTBase t : tagList) { - jAry.add(NBTtoJSON_Base(t, false)); - } + List tagList = getTagList((NBTTagList) tag); - return jAry; + for (NBTBase t : tagList) { + jAry.add(NBTtoJSON_Base(t, format)); } + + return jAry; } else if (tag instanceof NBTTagByteArray) { JsonArray jAry = new JsonArray(); From eb7bb00aab46fcfe11825f2854f088859bd71fa4 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 10 Oct 2025 03:23:56 +0800 Subject: [PATCH 013/160] Fix edge-case crash when loading trade history for an already-removed tradegroup. --- .../vendingmachine/blocks/gui/TradeMainPanel.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 c25667b..b7812d1 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -21,6 +21,7 @@ import com.cubefury.vendingmachine.network.handlers.NetResetVMUser; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeGroup; import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.BigItemStack; @@ -126,8 +127,11 @@ public Map> formatTrades() { Map> trades = new HashMap<>(); trades.put(TradeCategory.ALL, new ArrayList<>()); for (TradeItemDisplay tid : TradeManager.INSTANCE.tradeData) { - TradeCategory category = TradeDatabase.INSTANCE.getTradeGroupFromId(tid.tgID) - .getCategory(); + TradeGroup group = TradeDatabase.INSTANCE.getTradeGroupFromId(tid.tgID); + if (group == null) { + continue; + } + TradeCategory category = group.getCategory(); trades.putIfAbsent(category, new ArrayList<>()); trades.get(category) .add(tid); From 2dfa8592021452c057e7dc45779c84eec95cc943 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 10 Oct 2025 17:16:40 +0800 Subject: [PATCH 014/160] Add list trade display format --- .../com/cubefury/vendingmachine/Config.java | 13 ++ .../blocks/gui/MTEVendingMachineGui.java | 193 ++++++++++++++---- .../blocks/gui/TradeItemDisplayWidget.java | 107 ++++++++-- .../blocks/gui/TradeMainPanel.java | 2 +- .../vendingmachine/gui/GuiTextures.java | 31 ++- .../assets/vendingmachine/lang/en_US.lang | 3 + .../background/list_trade_button_pressed.png | Bin 0 -> 3183 bytes ...t_trade_button_pressed_color_corrected.png | Bin 0 -> 3210 bytes .../list_trade_button_unpressed.png | Bin 0 -> 3182 bytes ...trade_button_unpressed_color_corrected.png | Bin 0 -> 3211 bytes .../textures/gui/overlay/mode_list.png | Bin 0 -> 597 bytes .../textures/gui/overlay/mode_tile.png | Bin 0 -> 613 bytes 12 files changed, 285 insertions(+), 64 deletions(-) create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed.png create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed_color_corrected.png create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed.png create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed_color_corrected.png create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_list.png create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_tile.png diff --git a/src/main/java/com/cubefury/vendingmachine/Config.java b/src/main/java/com/cubefury/vendingmachine/Config.java index 8972650..d9f405f 100644 --- a/src/main/java/com/cubefury/vendingmachine/Config.java +++ b/src/main/java/com/cubefury/vendingmachine/Config.java @@ -4,6 +4,8 @@ import net.minecraftforge.common.config.Configuration; +import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplayWidget.DisplayType; + public class Config { private static final String CONFIG_CATEGORY_VM = "Vending Machine Settings"; @@ -13,6 +15,7 @@ public class Config { public static int gui_refresh_interval = 20; public static int dispense_frequency = 10; public static int dispense_amount = 16; + public static DisplayType display_type = DisplayType.TILE; public static File worldDir = null; @@ -36,6 +39,16 @@ public static void init(File configFile) { 1, Integer.MAX_VALUE, "Number of items per dispense cycle"); + try { + display_type = DisplayType.valueOf( + configuration.getString( + "display_type", + CONFIG_CATEGORY_VM, + "TILE", + "Default trade display format, either TILE or LIST. Case sensitive.")); + } catch (IllegalArgumentException e) { + display_type = DisplayType.TILE; + } if (configuration.hasChanged()) { configuration.save(); 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 e3a7b50..73bc0e0 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -13,14 +13,18 @@ import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; +import com.cleanroommc.modularui.drawable.DynamicDrawable; import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.screen.RichTooltip; import com.cleanroommc.modularui.screen.UISettings; import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.value.IntValue; import com.cleanroommc.modularui.value.sync.BooleanSyncValue; import com.cleanroommc.modularui.value.sync.PanelSyncManager; import com.cleanroommc.modularui.widget.ParentWidget; import com.cleanroommc.modularui.widget.SingleChildWidget; +import com.cleanroommc.modularui.widgets.CycleButtonWidget; import com.cleanroommc.modularui.widgets.ListWidget; import com.cleanroommc.modularui.widgets.PagedWidget; import com.cleanroommc.modularui.widgets.SlotGroupWidget; @@ -30,6 +34,7 @@ import com.cleanroommc.modularui.widgets.layout.Row; import com.cleanroommc.modularui.widgets.slot.ItemSlot; import com.cleanroommc.modularui.widgets.slot.ModularSlot; +import com.cubefury.vendingmachine.Config; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.gui.GuiTextures; @@ -57,7 +62,8 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { private boolean ejectItems = false; private boolean ejectCoins = false; private final Map ejectSingleCoin = new HashMap<>(); - private final Map> displayedTrades = new HashMap<>(); + private final Map> displayedTradesTiles = new HashMap<>(); + private final Map> displayedTradesList = new HashMap<>(); private final List tradeCategories = new ArrayList<>(); private final List inputSlots = new ArrayList<>(); @@ -67,12 +73,17 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { public static String lastSearch = ""; public static int lastPage = 0; + public static TradeItemDisplayWidget.DisplayType displayType = Config.display_type; public static final int CUSTOM_UI_HEIGHT = 320; - public static final int ITEMS_PER_ROW = 3; - public static final int ITEM_HEIGHT = 25; - public static final int ITEM_WIDTH = 47; + // Trade Item Display + public static final int TILE_ITEMS_PER_ROW = 3; + public static final int TILE_ITEM_HEIGHT = 25; + public static final int TILE_ITEM_WIDTH = 47; + public static final int LIST_ITEM_HEIGHT = 14; + public static final int LIST_ITEM_WIDTH = 153; + private static final int COIN_COLUMN_WIDTH = 40; private static final int COIN_COLUMN_ROW_COUNT = 4; @@ -88,10 +99,15 @@ public MTEVendingMachineGui(MTEVendingMachine base) { this.tradeCategories.addAll(TradeDatabase.INSTANCE.getTradeCategories()); for (TradeCategory c : this.tradeCategories) { - displayedTrades.put(c, new ArrayList<>(MTEVendingMachine.MAX_TRADES)); + displayedTradesTiles.put(c, new ArrayList<>(MTEVendingMachine.MAX_TRADES)); + for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { + displayedTradesTiles.get(c) + .add(new TradeItemDisplayWidget(null, TradeItemDisplayWidget.DisplayType.TILE)); + } + displayedTradesList.put(c, new ArrayList<>(MTEVendingMachine.MAX_TRADES)); for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { - displayedTrades.get(c) - .add(new TradeItemDisplayWidget(null)); + displayedTradesList.get(c) + .add(new TradeItemDisplayWidget(null, TradeItemDisplayWidget.DisplayType.LIST)); } } @@ -117,7 +133,8 @@ public ModularPanel build(PosGuiData guiData, PanelSyncManager syncManager, UISe .padding(4); panel.child(createCategoryTabs(this.tabController)); Flow mainColumn = new Column().width(170); - if (VendingMachine.proxy.isClient()) { // client side filtering + if (VendingMachine.proxy.isClient()) { // client side sort and filtering + panel.child(createQolButtonColumn()); mainColumn.child( createTitleTextStyle( IKey.lang("gt.blockmachines.multimachine.vendingmachine.name.gui") @@ -143,6 +160,32 @@ public void restorePreviousSettings() { this.searchBar.setText(lastSearch); } + public IWidget createQolButtonColumn() { + Flow buttonColumn = new Column().width(8) + .height(20) + .left(-17) + .top(1) + .coverChildren(); + buttonColumn.child( + new CycleButtonWidget().size(14) + .overlay( + new DynamicDrawable( + () -> displayType.getTexture() + .size(14))) + .stateCount(TradeItemDisplayWidget.DisplayType.values().length) + .value( + new IntValue.Dynamic( + () -> displayType.ordinal(), + val -> { displayType = TradeItemDisplayWidget.DisplayType.values()[val]; })) + .tooltipDynamic(builder -> { + builder.clearText(); + builder + .addLine(IKey.lang("vendingmachine.gui.display_mode") + " " + displayType.getLocalizedName()); + }) + .tooltipAutoUpdate(true)); + return buttonColumn; + } + public IWidget createCategoryTabs(PagedWidget.Controller tabController) { Flow tabColumn = new Column().width(40) .height(100) @@ -347,6 +390,45 @@ private SlotGroupWidget createOutputSlots() { .build(); } + private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { + if (cur != null) { + for (BigItemStack toItem : cur.toItems) { + builder.addLine( + IKey.str( + toItem.stackSize + " " + + toItem.getBaseStack() + .getDisplayName()) + .style(IKey.AQUA)); + // builder.add(new ItemDrawable(toItem.getBaseStack())); + } + builder.emptyLine(); + builder.addLine( + IKey.str(Translator.translate("vendingmachine.gui.required_inputs")) + .style(IKey.DARK_GREEN, IKey.ITALIC)); + for (CurrencyItem currencyItem : cur.fromCurrency) { + builder.addLine( + IKey.str(currencyItem.value + " " + currencyItem.type.getLocalizedName()) + .style(IKey.DARK_GREEN)); + } + for (BigItemStack fromItem : cur.fromItems) { + builder.addLine( + IKey.str( + fromItem.stackSize + " " + + fromItem.getBaseStack() + .getDisplayName()) + .style(IKey.DARK_GREEN)); + } + + builder.emptyLine(); + builder.addLine( + IKey.str(cur.label) + .style(IKey.GRAY)); + builder.addLine( + IKey.str(Translator.translate("vendingmachine.gui.trade_hint")) + .style(IKey.GRAY)); + } + } + // spotless:off private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller tabController) { PagedWidget paged = new PagedWidget<>() @@ -364,50 +446,60 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t tradeList.child(new Row().height(2)); // Higher first row top margin - Flow row = new TradeRow().height(ITEM_HEIGHT+2).left(2); + Flow row = new TradeRow().height(TILE_ITEM_HEIGHT +2).left(2); + // Tiles Display for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { int index = i; - displayedTrades.get(category).get(i).setRootPanel(rootPanel); - row.child(displayedTrades.get(category).get(i) + displayedTradesTiles.get(category).get(i).setRootPanel(rootPanel); + row.child(displayedTradesTiles.get(category).get(i) .tooltipDynamic(builder -> { builder.clearText(); - synchronized (displayedTrades) { - if (index < displayedTrades.get(category).size()) { - TradeItemDisplay cur = displayedTrades.get(category).get(index).getDisplay(); - if (cur != null) { - for (BigItemStack toItem : cur.toItems) { - builder.addLine(IKey.str(toItem.stackSize + " " + toItem.getBaseStack().getDisplayName()).style(IKey.AQUA)); - // builder.add(new ItemDrawable(toItem.getBaseStack())); - } - builder.emptyLine(); - builder.addLine(IKey.str(Translator.translate("vendingmachine.gui.required_inputs")).style(IKey.DARK_GREEN, IKey.ITALIC)); - for (CurrencyItem currencyItem: cur.fromCurrency) { - builder.addLine(IKey.str(currencyItem.value + " " + currencyItem.type.getLocalizedName()).style(IKey.DARK_GREEN)); - } - for (BigItemStack fromItem : cur.fromItems) { - builder.addLine(IKey.str(fromItem.stackSize + " " + fromItem.getBaseStack().getDisplayName()).style(IKey.DARK_GREEN)); - } - - builder.emptyLine(); - builder.addLine(IKey.str(cur.label).style(IKey.GRAY)); - builder.addLine(IKey.str(Translator.translate("vendingmachine.gui.trade_hint")).style(IKey.GRAY)); + synchronized (displayedTradesTiles) { + if (index < displayedTradesTiles.get(category).size()) { + constructTradeTooltip(builder, displayedTradesTiles.get(category).get(index).getDisplay()); } } - } }) .tooltipAutoUpdate(true) - .setEnabledIf(slot -> ((TradeItemDisplayWidget) slot).getDisplay() != null) + .setEnabledIf(slot -> { + TradeItemDisplayWidget display = ((TradeItemDisplayWidget) slot); + return displayType == display.displayType && display.getDisplay() != null; + }) .margin(2)); - if (i % ITEMS_PER_ROW == ITEMS_PER_ROW - 1) { + if (i % TILE_ITEMS_PER_ROW == TILE_ITEMS_PER_ROW - 1) { tradeList.child(row); - row = new TradeRow().height(ITEM_HEIGHT+2).left(2); + row = new TradeRow().height(TILE_ITEM_HEIGHT +2).left(2); } } if (row.hasChildren()) { tradeList.child(row); } + + // List Display + row = new TradeRow().height(LIST_ITEM_HEIGHT).left(2); + for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { + int index = i; + displayedTradesList.get(category).get(i).setRootPanel(rootPanel); + row.child(displayedTradesList.get(category).get(i) + .tooltipDynamic(builder -> { + builder.clearText(); + synchronized (displayedTradesList) { + if (index < displayedTradesList.get(category).size()) { + constructTradeTooltip(builder, displayedTradesList.get(category).get(index).getDisplay()); + } + } + }) + .tooltipAutoUpdate(true) + .setEnabledIf(slot -> { + TradeItemDisplayWidget display = ((TradeItemDisplayWidget) slot); + return displayType == display.displayType && display.getDisplay() != null; + })); + tradeList.child(row); + row = new TradeRow().height(LIST_ITEM_HEIGHT).left(2); + } + tradeList.child(new Row().height(2)); // bottom padding for last row paged.addPage(tradeList); } @@ -537,9 +629,10 @@ public static void resetForceRefresh() { forceRefresh = false; } - public void updateTradeDisplay(Map> trades) { - synchronized (displayedTrades) { - for (Map.Entry> entry : displayedTrades.entrySet()) { + private void updateTradeDisplay(Map> trades, + Map> display) { + synchronized (display) { + for (Map.Entry> entry : display.entrySet()) { int displayedSize = trades.get(entry.getKey()) == null ? 0 : trades.get(entry.getKey()) .size(); @@ -560,10 +653,16 @@ public void updateTradeDisplay(Map> trades } } - public Map> getTradeDisplayData() { + public void updateTradeDisplay(Map> trades) { + this.updateTradeDisplay(trades, displayedTradesTiles); + this.updateTradeDisplay(trades, displayedTradesList); + } + + public Map> getCurrentTradeDisplayData() { Map> currentData = new HashMap<>(); - synchronized (displayedTrades) { - this.displayedTrades.forEach((k, v) -> { + + synchronized (displayedTradesTiles) { + this.displayedTradesTiles.forEach((k, v) -> { currentData.put( k, v.stream() @@ -572,6 +671,18 @@ public Map> getTradeDisplayData() { .collect(Collectors.toList())); }); } + + synchronized (displayedTradesList) { + this.displayedTradesList.forEach((k, v) -> { + currentData.get(k) + .addAll( + v.stream() + .map(TradeItemDisplayWidget::getDisplay) + .filter(Objects::nonNull) + .collect(Collectors.toList())); + }); + } + return currentData; } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 65641ef..66c1d36 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -1,5 +1,8 @@ package com.cubefury.vendingmachine.blocks.gui; +import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_LIST; +import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_TILE; + import net.minecraft.item.ItemStack; import org.jetbrains.annotations.NotNull; @@ -9,6 +12,8 @@ import com.cleanroommc.modularui.api.widget.Interactable; import com.cleanroommc.modularui.drawable.DynamicDrawable; import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.drawable.Icon; +import com.cleanroommc.modularui.drawable.UITexture; import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; import com.cleanroommc.modularui.theme.WidgetTheme; import com.cleanroommc.modularui.utils.Platform; @@ -19,17 +24,51 @@ public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { + public enum DisplayType { + + TILE("tile", MODE_TILE), + LIST("list", MODE_LIST); + + private String type; + private Icon texture; + + DisplayType(String type, UITexture texture) { + this.type = type; + this.texture = texture.asIcon(); + } + + public String getLocalizedName() { + return IKey.lang("vendingmachine.gui.display_mode_" + this.type) + .toString(); + } + + public Icon getTexture() { + return this.texture; + } + } + private TradeMainPanel rootPanel; private boolean pressed = false; private IValue value; + public final DisplayType displayType; private TradeItemDisplay display; - public TradeItemDisplayWidget(TradeItemDisplay display) { - height(MTEVendingMachineGui.ITEM_HEIGHT); - width(MTEVendingMachineGui.ITEM_WIDTH); - background( - new DynamicDrawable(() -> pressed ? GuiTextures.TRADE_BUTTON_PRESSED : GuiTextures.TRADE_BUTTON_UNPRESSED)); + public TradeItemDisplayWidget(TradeItemDisplay display, DisplayType displayType) { + this.displayType = displayType; + if (displayType == DisplayType.TILE) { + height(MTEVendingMachineGui.TILE_ITEM_HEIGHT); + width(MTEVendingMachineGui.TILE_ITEM_WIDTH); + background( + new DynamicDrawable( + () -> pressed ? GuiTextures.TILE_TRADE_BUTTON_PRESSED : GuiTextures.TILE_TRADE_BUTTON_UNPRESSED)); + } else if (displayType == DisplayType.LIST) { + height(MTEVendingMachineGui.LIST_ITEM_HEIGHT); + width(MTEVendingMachineGui.LIST_ITEM_WIDTH); + background( + new DynamicDrawable( + () -> pressed ? GuiTextures.LIST_TRADE_BUTTON_PRESSED : GuiTextures.LIST_TRADE_BUTTON_UNPRESSED)); + } this.display = display; this.item((ItemStack) null); @@ -57,24 +96,52 @@ public TradeItemDisplay getDisplay() { public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { ItemStack item = value.getValue(); if (!Platform.isStackEmpty(item)) { - GuiDraw.drawText(" " + this.display.display.stackSize, 4, 9, 1.0f, 0x0, false); - GuiDraw.drawItem(item, 26, 4, 16, 16, context.getCurrentDrawingZ()); - if (this.display.tradeableNow) { - GuiDraw.drawOutline(1, 1, 45, 23, 0x883CFF00, 2); - } - if (this.display.hasCooldown || !this.display.enabled) { - GuiDraw.drawRoundedRect( - 1, + if (this.displayType == DisplayType.TILE) { + GuiDraw.drawText(" " + this.display.display.stackSize, 4, 9, 1.0f, 0x0, false); + GuiDraw.drawItem(item, 26, 4, 16, 16, context.getCurrentDrawingZ()); + if (this.display.tradeableNow) { + GuiDraw.drawOutline(1, 1, 45, 23, 0x883CFF00, 2); + } + if (this.display.hasCooldown || !this.display.enabled) { + GuiDraw.drawRoundedRect( + 1, + 1, + MTEVendingMachineGui.TILE_ITEM_WIDTH - 2, + MTEVendingMachineGui.TILE_ITEM_HEIGHT - 2, + 0xBB000000, + 1, + 1); + } + this.overlay( + IKey.str(display.hasCooldown ? this.display.cooldownText : "") + .style(IKey.WHITE)); + } else if (this.displayType == DisplayType.LIST) { + GuiDraw.drawText( + " " + this.display.display.stackSize + " " + this.display.display.getDisplayName(), + 4, + 4, + 0.9f, + 0x0, + false); + GuiDraw.drawRect( 1, - MTEVendingMachineGui.ITEM_WIDTH - 2, - MTEVendingMachineGui.ITEM_HEIGHT - 2, - 0xBB000000, 1, - 1); + 3, + MTEVendingMachineGui.LIST_ITEM_HEIGHT - 3, + this.display.tradeableNow ? 0x883CFF00 : 0x88333333); + if (this.display.hasCooldown || !this.display.enabled) { + GuiDraw.drawRect( + 1, + 1, + MTEVendingMachineGui.LIST_ITEM_WIDTH - 2, + MTEVendingMachineGui.LIST_ITEM_HEIGHT - 2, + 0xBB000000); + } + this.overlay( + IKey.str(display.hasCooldown ? this.display.cooldownText : "") + .style(IKey.WHITE) + .scale(0.9f)); } - this.overlay( - IKey.str(display.hasCooldown ? this.display.cooldownText : "") - .style(IKey.WHITE)); } } 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 b7812d1..e663327 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -65,7 +65,7 @@ public boolean onKeyRelease(char typedChar, int keyCode) { public void updateGui() { if (shiftHeld) { - this.updateTradeInformation(gui.getTradeDisplayData()); + this.updateTradeInformation(gui.getCurrentTradeDisplayData()); } else { Map> trades = formatTrades(); gui.updateTradeDisplay(trades); diff --git a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java index 8ee5829..c020280 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java @@ -45,20 +45,47 @@ public final class GuiTextures { .name("text_field_background") .build(); - public static final UITexture TRADE_BUTTON_UNPRESSED = UITexture.builder() + // TODO: Restore canApplyTheme to trade button textures after scrolling texture bug is fixed in MUI2 + public static final UITexture TILE_TRADE_BUTTON_UNPRESSED = UITexture.builder() .location(VendingMachine.MODID, "gui/background/trade_button_unpressed_color_corrected") .imageSize(195, 136) .adaptable(4) .name("trade_button_unpressed") .build(); - public static final UITexture TRADE_BUTTON_PRESSED = UITexture.builder() + public static final UITexture TILE_TRADE_BUTTON_PRESSED = UITexture.builder() .location(VendingMachine.MODID, "gui/background/trade_button_pressed_color_corrected") .imageSize(195, 136) .adaptable(4) .name("trade_button_pressed") .build(); + public static final UITexture LIST_TRADE_BUTTON_UNPRESSED = UITexture.builder() + .location(VendingMachine.MODID, "gui/background/list_trade_button_unpressed_color_corrected") + .imageSize(195, 136) + .adaptable(2) + .name("list_trade_button_unpressed") + .build(); + + public static final UITexture LIST_TRADE_BUTTON_PRESSED = UITexture.builder() + .location(VendingMachine.MODID, "gui/background/list_trade_button_pressed_color_corrected") + .imageSize(195, 136) + .adaptable(2) + .name("list_trade_button_pressed") + .build(); + + public static final UITexture MODE_TILE = UITexture.builder() + .location(VendingMachine.MODID, "gui/overlay/mode_tile") + .imageSize(32, 32) + .name("mode_tile") + .build(); + + public static final UITexture MODE_LIST = UITexture.builder() + .location(VendingMachine.MODID, "gui/overlay/mode_list") + .imageSize(32, 32) + .name("mode_list") + .build(); + public static final UITexture INPUT_SPRITE = UITexture.builder() .location(VendingMachine.MODID, "gui/background/input") .imageSize(30, 20) diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 0583853..c5cc5ea 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -17,6 +17,9 @@ vendingmachine.gui.single_coin_type_eject_hint=Shift-Click to Extract vendingmachine.gui.search=Search vendingmachine.gui.required_inputs=Requires: vendingmachine.gui.trade_hint=Shift-Click to Purchase +vendingmachine.gui.display_mode=Display: +vendingmachine.gui.display_mode_tile=Tiles +vendingmachine.gui.display_mode_list=List vendingmachine.gui.cooldown_display.second=s vendingmachine.gui.cooldown_display.minute=m diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed.png b/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..aefd2f76dd49a5b1b1d181bca0e76d0831b0e7ab GIT binary patch literal 3183 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed.png b/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed.png new file mode 100644 index 0000000000000000000000000000000000000000..48b5d2275de7fa1a5cc90b9ed44096a70153a956 GIT binary patch literal 3182 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed_color_corrected.png b/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed_color_corrected.png new file mode 100644 index 0000000000000000000000000000000000000000..e931d75bdf6a09fa21f0cb1fa1657e1299308aaf GIT binary patch literal 3211 zcmd5;=|9wq7ycrI>{}DrvP@ZL(%7@iU~Jh9LZb<}VJ6144zjOvL&?5mE3PComPTZc zG4?2B>mssmV^BZ$Pq^=XFV6Fv=Q+>kyg6@9lGQC^PWDUe003~BAQ3ia+<8`s=UL9s zdF~GL8J+Xex6lWGy1zJ1+|M+-nl~J76<}j*AYoz%he0%8Fh!^m1OSjp1zACMw$nlh zRI(b`DuXBa$?${wHjGG4GBRE18ib9#8F^=xjQi} z#S6{KaA6Bz@&V>>_4NiqG$Y0w#_*|BpB#RgFu8?G;^_F=m~LtZ@Vn?qvy&7Au*yzd z-l0vqfQ0+ibx`>-B+LHnx2hIHDyBnHPSH?@%zzz*+u;W}9^4wc&{%EIK)}#~$JX~5 zxy3XMzP8kKG)Q>)JgphpCX0!|o5bt&V87Ra!f(Ls5GcINfMGvkjuWZtbxFX?q!l^cG zUpN1858lmG&%i_AZfbs>p%sX(zM%!&(S@a=1e!SOuRt*&-V^DzMCB)jh=B@o3G=MR z+kO0r%sB?}dbFZk8h7Wfvgzimq|Y?o;VehSa>+}25n=%N8m|Of*gg5-O#(-cG1Czx zWh5uN;Fucyi-2k}|J5fX9ZAF(BcM%u)+P`rd2(W6(;`nb8p*un*i=P zCPsa5;<<-t$Xv9*V+MqTus~E}@x>?6HE6jPEP=(msxdI!Mf@YooT@sj(xUzV7i5Vk!K6Zn7bDF@Wd-XQ>p}G*V?>QOP*19RMV;f{nvA3sObtGDr7zQh61jrSU&2W4FLy%xsB_3-7gAxu1bXJ-1)i+g*J z3jB@0(?FS){g#-P>!CfN)}e8s>!F8xY;=WF>C?+}GToL%lSPt+nWct>#JL@>&?(UA z8h;vJo0gh(Hx+g<5TpZjxXz_Aq~>>{?STR8p_-HDDB7PQfcXfuxc=2Qbov6UUd;?r z4H1DRP%aNLFSSw<6o-Xw2^plYq==aFjb-L^`gjnXM-^ifITTwJikv`>-M4+~S4s5y zzSsi4ulEVP@pt*}+uk3;>{i$0D1Lg|bMV<^$7Qy;dihT(!OzRDm-Gb_G*rd!&M^mB=J9H#*NOa%9bxai@i;q{Wk52>A5 zaRhN98#hNSTjWJ|erukQ_fakA{^%^`S}C&BfYc@;2VwF&v{bN^|9M{No!;QyC%s5a z&0SQFTk=>Ue^+2HX0dcJZ=q6{t}xS#)9$!gqCQWTS~LtvQBs(6%x|O7__}5CWsLbo zk|0TnNt+ra`7A?wqfzCJW|d7o8%i7eg{)XsY{uqCStztg z-?3{Kvg0VMq*qRsx835f_)>ImRY#Vr!}KgY`=K3@w}R~$+IW2znovJjpIl!ykpFDm z1t!DJcf$ido${u&TXmW`9@T|-;|9%L%(Bhgl~vO`L>BrNs$kL0(>oReayx|G_im4z zJ6uO@7vFyU7L6}o{z$hUt}3q%MXl8;IqS6bU@4CpV;j96M1mWX6qLi8l{{T7(;Y@~ zpV#e2tldr#Og8LRgEjfQ_>%Y;Jf+^`y-`tRA#N5dBWzY zXz+MFSmHx<7<8DQT>COZx(r4sQI*BNh`k{Puwsn+iO;m2{d{NTj!w*)uJ~kq3`KKET!?uglvMw zu^7xq?I4muZ)r9uecAA%Gh#mC$D>3h0)_*7#n zNzcR>6QmQwBJ*hL`~yA{bJ_wLvs#O{?Z#=WuxIb~fpTJVXcw4L|KFHnQ z1Au$@1cU@g*y024d1EE)uvnjt%K2~rV0dPN(6XaeR!*?Wcl+W(we?vFd*OSQLnU}M;Xv?kr>UdpKnQEyEnZbUV$U`Tc zhUbz#rCgk&UVQ7jgoA9O-(BE==;fQ7K^MTwg!otehemf*|39Sv)9U}D@R49=L`czT lxHFk8>xk&S&qL#G1OA@!G2ei7TtB-cU}AU+@yY-l{Xc^Ew6OpH literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_list.png b/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_list.png new file mode 100644 index 0000000000000000000000000000000000000000..039e5ef7a8733fa20e80b8c60c2b82adb5a41d7e GIT binary patch literal 597 zcmV-b0;>IqP)1q~8j=(jN5Qq=;KyRs!Nplu2UkH5`~Y!ua#D1W691PJTEuv8+>dwn9(V5mp;2L) z6&eRL-8R$7gqY2(is4rX2qB7o1Y~9zbCQ&T@A$e$fUkFPp5=e;&(W*qEd~Tc;#p>x zHt`1W^rmfa-Y1T-lB^P+6OWm6LE=ZQD;~dbF1jr6%&3`3&l5+9#bO659n4CmMm$9v zQ#GCPg{;Ra=Pk}!rN&zKyGn%>^RL6AovVi>1}_t z0nB`oUT${ujJ0}MVHvMIY#kfu;50Pkn?O*vrT7U)^?dTZ_D^a03F zSE(D|;1C!sQueyfySqDk`}a(%zaQGQa%$ya9j jfP6v#azJ+g0LTFkXY-H2qYs)-00000NkvXXu0mjf!kqM0 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_tile.png b/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_tile.png new file mode 100644 index 0000000000000000000000000000000000000000..426e54fd832ed051320122c44661b4d207a3cf32 GIT binary patch literal 613 zcmV-r0-F7aP)1q~8j=(jN5Qq=;KyRs!Nplu2UkH5`~Y!ua#D1W691PJTEuv8+>dwn9(V5mp;2L) z6&eRL-8R$7gqY2(is4rX2qB7o1Y~9zbCQ&T@A$e$fUkFPp5=e;&(W*qEd~Tc;#p>x zHt`1W^rmfa-Y1T-lB^P+6OWm6LE=ZQD;~dbF1jr6%&3`3&l5+9#bO659n4CmMm$9v zQ#GCPg{;Ra=Pk}!rN&zKyGn%>^RL6AovVi>1}_t z0nB`oUT${ujJ0}MVHvMIY#kfu;50Pkn?O*vrT7U)^?dTZ_D^a03F zSE(D|;1C!sQueyfySqDk`}a(%zaQGQa%$yP)ITUB@t=3 z1El1xp;h7n++Pp|;9f%j0FaWqhE@Rp0C&I!j|o4}b*$wK00000NkvXXu0mjf<%9f+ literal 0 HcmV?d00001 From e9c7a7ef2d005a992ceb03c451fdaf2fa5fa506d Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 10 Oct 2025 17:48:42 +0800 Subject: [PATCH 015/160] Added alphabetical sort order --- .../com/cubefury/vendingmachine/Config.java | 12 +++++ .../blocks/gui/MTEVendingMachineGui.java | 44 ++++++++++++++++ .../blocks/gui/TradeMainPanel.java | 49 +++++++++++------- .../vendingmachine/gui/GuiTextures.java | 12 +++++ .../assets/vendingmachine/lang/en_US.lang | 3 ++ .../textures/gui/overlay/sort_alphabet.png | Bin 0 -> 765 bytes .../textures/gui/overlay/sort_smart.png | Bin 0 -> 339 bytes 7 files changed, 100 insertions(+), 20 deletions(-) create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_alphabet.png create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_smart.png diff --git a/src/main/java/com/cubefury/vendingmachine/Config.java b/src/main/java/com/cubefury/vendingmachine/Config.java index d9f405f..d812ea9 100644 --- a/src/main/java/com/cubefury/vendingmachine/Config.java +++ b/src/main/java/com/cubefury/vendingmachine/Config.java @@ -4,6 +4,7 @@ import net.minecraftforge.common.config.Configuration; +import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplayWidget.DisplayType; public class Config { @@ -16,6 +17,7 @@ public class Config { public static int dispense_frequency = 10; public static int dispense_amount = 16; public static DisplayType display_type = DisplayType.TILE; + public static MTEVendingMachineGui.SortMode sort_mode = MTEVendingMachineGui.SortMode.SMART; public static File worldDir = null; @@ -49,6 +51,16 @@ public static void init(File configFile) { } catch (IllegalArgumentException e) { display_type = DisplayType.TILE; } + try { + sort_mode = MTEVendingMachineGui.SortMode.valueOf( + configuration.getString( + "sort_mode", + CONFIG_CATEGORY_VM, + "SMART", + "Default sort mode, either SMART or ALPHABET. Case sensitive.")); + } catch (IllegalArgumentException e) { + sort_mode = MTEVendingMachineGui.SortMode.SMART; + } if (configuration.hasChanged()) { configuration.save(); 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 73bc0e0..a3d3f66 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -1,5 +1,8 @@ package com.cubefury.vendingmachine.blocks.gui; +import static com.cubefury.vendingmachine.gui.GuiTextures.SORT_ALPHABET; +import static com.cubefury.vendingmachine.gui.GuiTextures.SORT_SMART; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -14,6 +17,8 @@ import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; import com.cleanroommc.modularui.drawable.DynamicDrawable; +import com.cleanroommc.modularui.drawable.Icon; +import com.cleanroommc.modularui.drawable.UITexture; import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.RichTooltip; @@ -74,6 +79,7 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { public static String lastSearch = ""; public static int lastPage = 0; public static TradeItemDisplayWidget.DisplayType displayType = Config.display_type; + public static SortMode sortMode = Config.sort_mode; public static final int CUSTOM_UI_HEIGHT = 320; @@ -87,6 +93,29 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { private static final int COIN_COLUMN_WIDTH = 40; private static final int COIN_COLUMN_ROW_COUNT = 4; + public enum SortMode { + + SMART("smart", SORT_SMART), + ALPHABET("alphabet", SORT_ALPHABET); + + private String mode; + private Icon texture; + + SortMode(String mode, UITexture texture) { + this.mode = mode; + this.texture = texture.asIcon(); + } + + public String getLocalizedName() { + return IKey.lang("vendingmachine.gui.display_sort_" + this.mode) + .toString(); + } + + public Icon getTexture() { + return this.texture; + } + } + public MTEVendingMachineGui(MTEVendingMachine base) { super(base); this.base = base; @@ -183,6 +212,21 @@ public IWidget createQolButtonColumn() { .addLine(IKey.lang("vendingmachine.gui.display_mode") + " " + displayType.getLocalizedName()); }) .tooltipAutoUpdate(true)); + buttonColumn.child( + new CycleButtonWidget().size(14) + .top(17) + .overlay( + new DynamicDrawable( + () -> sortMode.getTexture() + .size(14))) + .stateCount(SortMode.values().length) + .value(new IntValue.Dynamic(() -> sortMode.ordinal(), val -> { sortMode = SortMode.values()[val]; })) + .tooltipDynamic(builder -> { + builder.clearText(); + builder.addLine(IKey.lang("vendingmachine.gui.display_sort") + " " + sortMode.getLocalizedName()); + setForceRefresh(); + }) + .tooltipAutoUpdate(true)); return buttonColumn; } 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 e663327..37cbccc 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -126,6 +126,8 @@ public ItemStack convertToItemStack(BigItemStack stack) { public Map> formatTrades() { Map> trades = new HashMap<>(); trades.put(TradeCategory.ALL, new ArrayList<>()); + MTEVendingMachineGui.SortMode sortMode = MTEVendingMachineGui.sortMode; + for (TradeItemDisplay tid : TradeManager.INSTANCE.tradeData) { TradeGroup group = TradeDatabase.INSTANCE.getTradeGroupFromId(tid.tgID); if (group == null) { @@ -156,28 +158,35 @@ public Map> formatTrades() { if (a.display.getItem() == null) return 1; if (b.display.getItem() == null) return -1; - // enabled or has cooldown - int rankA = getRank(a); - int rankB = getRank(b); - - if (rankA != rankB) { - return Integer.compare(rankA, rankB); + if (sortMode == MTEVendingMachineGui.SortMode.ALPHABET) { + return (a.display.getDisplayName() + .compareTo(b.display.getDisplayName())); + } else if (sortMode == MTEVendingMachineGui.SortMode.SMART) { + // enabled or has cooldown + int rankA = getRank(a); + int rankB = getRank(b); + + if (rankA != rankB) { + return Integer.compare(rankA, rankB); + } + + // cooldown time + int cooldownCmp = Long.compare(b.cooldown, a.cooldown); + if (cooldownCmp != 0) return cooldownCmp; + + // display item ordering + int idCmp = Integer + .compare(Item.getIdFromItem(a.display.getItem()), Item.getIdFromItem(b.display.getItem())); + if (idCmp != 0) return idCmp; + int dmgCmp = Integer.compare(a.display.getItemDamage(), b.display.getItemDamage()); + if (dmgCmp != 0) return dmgCmp; + + // sort by tradegroup Order + return Integer.compare(a.tradeGroupOrder, b.tradeGroupOrder); } - // cooldown time - int cooldownCmp = Long.compare(b.cooldown, a.cooldown); - if (cooldownCmp != 0) return cooldownCmp; - - // display item ordering - int idCmp = Integer - .compare(Item.getIdFromItem(a.display.getItem()), Item.getIdFromItem(b.display.getItem())); - if (idCmp != 0) return idCmp; - int dmgCmp = Integer.compare(a.display.getItemDamage(), b.display.getItemDamage()); - if (dmgCmp != 0) return dmgCmp; - - // sort by tradegroup Order - return Integer.compare(a.tradeGroupOrder, b.tradeGroupOrder); - + // impossible + return 0; }); trades.replace(category, filteredTrades); } diff --git a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java index c020280..3de4571 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java @@ -86,6 +86,18 @@ public final class GuiTextures { .name("mode_list") .build(); + public static final UITexture SORT_SMART = UITexture.builder() + .location(VendingMachine.MODID, "gui/overlay/sort_smart") + .imageSize(32, 32) + .name("sort_smart") + .build(); + + public static final UITexture SORT_ALPHABET = UITexture.builder() + .location(VendingMachine.MODID, "gui/overlay/sort_alphabet") + .imageSize(32, 32) + .name("sort_alphabet") + .build(); + public static final UITexture INPUT_SPRITE = UITexture.builder() .location(VendingMachine.MODID, "gui/background/input") .imageSize(30, 20) diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index c5cc5ea..1162c3d 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -20,6 +20,9 @@ vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.display_mode=Display: vendingmachine.gui.display_mode_tile=Tiles vendingmachine.gui.display_mode_list=List +vendingmachine.gui.display_sort=Sort: +vendingmachine.gui.display_sort_smart=Smart +vendingmachine.gui.display_sort_alphabet=Alphabetical Order vendingmachine.gui.cooldown_display.second=s vendingmachine.gui.cooldown_display.minute=m diff --git a/src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_alphabet.png b/src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_alphabet.png new file mode 100644 index 0000000000000000000000000000000000000000..19f0991e96f6fa1ad5d77b9f1b9cf1c4de96f2df GIT binary patch literal 765 zcmV1q~8j=(jN5Qq=;KyRs!Nplu2UkH5`~Y!ua#D1W691PJTEuv8+>dwn9(V5mp;2L) z6&eRL-8R$7gqY2(is4rX2qB7o1Y~9zbCQ&T@A$e$fUkFPp5=e;&(W*qEd~Tc;#p>x zHt`1W^rmfa-Y1T-lB^P+6OWm6LE=ZQD;~dbF1jr6%&3`3&l5+9#bO659n4CmMm$9v zQ#GCPg{;Ra=Pk}!rN&zKyGn%>^RL6AovVi>1}_t z0nB`oUT${ujJ0}MVHvMIY#kfu;50Pkn?O*vrT7U)^?dTZ_D^a03F zSE(D|;1C!sQueyfySqDk`}a(%zaQGQa%$y zgCGtR6b~kj;Rx*pb`!e=35ULJU^id{H?RjWAw=bAr1ro|y!hww`w&s| zeUBqcBtQZrKmyDGWKqt_NGsvocLhMq@rbm_{~I8S^5s4-(WC-kEF_mjdA8@4s$K&a zPt>HwHm;iS_2qxbR;3Us5td9{a|VtDxB+Mv v#_LF{PfS3l_TP%5{SALr36KB@a5&%#lEEL)+t!YV00000NkvXXu0mjfu%1ND literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_smart.png b/src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_smart.png new file mode 100644 index 0000000000000000000000000000000000000000..7df0dc2e83fa17a7016d234d5eb0733ec4ecd43c GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oArNM~bhqvgP*A$W zHKHUqKdq!Zu_%?nIW?!avREOwq%eANX_uGre3zY_)%z;53->dA^J4tfW_W7nJLfCULz|ZU)a8uo{>{5VakFl$`Y}y^ z&0T5F!r7uqr9N-(zRPe!p!i110#Wak3=B6F|LnM-+rTTi{^f_% Date: Fri, 10 Oct 2025 18:03:01 +0800 Subject: [PATCH 016/160] Separated Item and Item Count in list mode. --- .../blocks/gui/TradeItemDisplayWidget.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 66c1d36..4a4c680 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -116,13 +116,8 @@ public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { IKey.str(display.hasCooldown ? this.display.cooldownText : "") .style(IKey.WHITE)); } else if (this.displayType == DisplayType.LIST) { - GuiDraw.drawText( - " " + this.display.display.stackSize + " " + this.display.display.getDisplayName(), - 4, - 4, - 0.9f, - 0x0, - false); + GuiDraw.drawText("" + this.display.display.stackSize, 6, 4, 0.9f, 0x0, false); + GuiDraw.drawText("" + this.display.display.getDisplayName(), 24, 4, 0.9f, 0x0, false); GuiDraw.drawRect( 1, 1, From 8711e4677e8685cc79840a8b07afff16926851a3 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 10 Oct 2025 22:02:54 +0800 Subject: [PATCH 017/160] Separated Item and Item Count in list mode. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c193ac2..e91cd13 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Alpha Testing This can be used as a standalone mod with several dependencies. The vending machine block and ME Vending Uplink do not come with default recipes. ### Required Dependencies: -- GT5U +- GT5Unofficial-GTNH (Not compatible with main GT5U branch!) - ModularUI 2 - NotEnoughItems - Applied Energistics 2 From 15dfef509dcd26eac0ee5f95fe435ea824b66094 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 11 Oct 2025 02:45:36 +0800 Subject: [PATCH 018/160] Changes: - Added Color settings for VM displayed text - Added small icon next to name of tradeable item --- .../com/cubefury/vendingmachine/Config.java | 12 ++++++++++++ .../blocks/gui/TradeItemDisplayWidget.java | 18 +++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/Config.java b/src/main/java/com/cubefury/vendingmachine/Config.java index d812ea9..4e50247 100644 --- a/src/main/java/com/cubefury/vendingmachine/Config.java +++ b/src/main/java/com/cubefury/vendingmachine/Config.java @@ -16,6 +16,7 @@ public class Config { public static int gui_refresh_interval = 20; public static int dispense_frequency = 10; public static int dispense_amount = 16; + public static int display_text_color = 0x0; public static DisplayType display_type = DisplayType.TILE; public static MTEVendingMachineGui.SortMode sort_mode = MTEVendingMachineGui.SortMode.SMART; @@ -41,6 +42,17 @@ public static void init(File configFile) { 1, Integer.MAX_VALUE, "Number of items per dispense cycle"); + + try { + display_text_color = Integer.decode( + configuration.getString( + "display_text_color", + CONFIG_CATEGORY_VM, + "0x0", + "Color for text in Vending Machine GUI.")); + } catch (NumberFormatException e) { + display_text_color = 0x0; + } try { display_type = DisplayType.valueOf( configuration.getString( diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 4a4c680..e9b9570 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -20,6 +20,7 @@ import com.cleanroommc.modularui.value.sync.GenericSyncValue; import com.cleanroommc.modularui.value.sync.SyncHandler; import com.cleanroommc.modularui.widgets.ItemDisplayWidget; +import com.cubefury.vendingmachine.Config; import com.cubefury.vendingmachine.gui.GuiTextures; public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { @@ -97,7 +98,7 @@ public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { ItemStack item = value.getValue(); if (!Platform.isStackEmpty(item)) { if (this.displayType == DisplayType.TILE) { - GuiDraw.drawText(" " + this.display.display.stackSize, 4, 9, 1.0f, 0x0, false); + GuiDraw.drawText(" " + this.display.display.stackSize, 4, 9, 1.0f, Config.display_text_color, false); GuiDraw.drawItem(item, 26, 4, 16, 16, context.getCurrentDrawingZ()); if (this.display.tradeableNow) { GuiDraw.drawOutline(1, 1, 45, 23, 0x883CFF00, 2); @@ -116,8 +117,19 @@ public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { IKey.str(display.hasCooldown ? this.display.cooldownText : "") .style(IKey.WHITE)); } else if (this.displayType == DisplayType.LIST) { - GuiDraw.drawText("" + this.display.display.stackSize, 6, 4, 0.9f, 0x0, false); - GuiDraw.drawText("" + this.display.display.getDisplayName(), 24, 4, 0.9f, 0x0, false); + GuiDraw.drawText("" + this.display.display.stackSize, 6, 4, 0.9f, Config.display_text_color, false); + GuiDraw.drawItem(item, 24, 2, 9, 9, context.getCurrentDrawingZ()); + GuiDraw.drawText( + this.display.display.getDisplayName() + .length() > 21 + ? this.display.display.getDisplayName() + .substring(0, 21) + "..." + : this.display.display.getDisplayName(), + 36, + 4, + 0.9f, + Config.display_text_color, + false); GuiDraw.drawRect( 1, 1, From 6bda1e8f514ab0c21ea971804ec20822892d8ff3 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Fri, 10 Oct 2025 21:21:05 +0200 Subject: [PATCH 019/160] update --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 9bd54c8..80be233 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.6-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.9-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") // implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.21:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.24:dev") } // deps may transitively add Baubles, so we replace it From e2aed96abe339ae52a7f274079c7b84ce634bbec Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 11 Oct 2025 03:33:06 +0800 Subject: [PATCH 020/160] Shifted text color setting to lang file --- src/main/java/com/cubefury/vendingmachine/Config.java | 11 ----------- .../blocks/gui/TradeItemDisplayWidget.java | 9 +++++---- .../resources/assets/vendingmachine/lang/en_US.lang | 2 +- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/Config.java b/src/main/java/com/cubefury/vendingmachine/Config.java index 4e50247..3e4af3e 100644 --- a/src/main/java/com/cubefury/vendingmachine/Config.java +++ b/src/main/java/com/cubefury/vendingmachine/Config.java @@ -16,7 +16,6 @@ public class Config { public static int gui_refresh_interval = 20; public static int dispense_frequency = 10; public static int dispense_amount = 16; - public static int display_text_color = 0x0; public static DisplayType display_type = DisplayType.TILE; public static MTEVendingMachineGui.SortMode sort_mode = MTEVendingMachineGui.SortMode.SMART; @@ -43,16 +42,6 @@ public static void init(File configFile) { Integer.MAX_VALUE, "Number of items per dispense cycle"); - try { - display_text_color = Integer.decode( - configuration.getString( - "display_text_color", - CONFIG_CATEGORY_VM, - "0x0", - "Color for text in Vending Machine GUI.")); - } catch (NumberFormatException e) { - display_text_color = 0x0; - } try { display_type = DisplayType.valueOf( configuration.getString( diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index e9b9570..ebb0549 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -20,8 +20,8 @@ import com.cleanroommc.modularui.value.sync.GenericSyncValue; import com.cleanroommc.modularui.value.sync.SyncHandler; import com.cleanroommc.modularui.widgets.ItemDisplayWidget; -import com.cubefury.vendingmachine.Config; import com.cubefury.vendingmachine.gui.GuiTextures; +import com.cubefury.vendingmachine.util.Translator; public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { @@ -95,10 +95,11 @@ public TradeItemDisplay getDisplay() { @Override public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { + int textColor = Translator.getColor("vendingmachine.gui.display_text_color"); ItemStack item = value.getValue(); if (!Platform.isStackEmpty(item)) { if (this.displayType == DisplayType.TILE) { - GuiDraw.drawText(" " + this.display.display.stackSize, 4, 9, 1.0f, Config.display_text_color, false); + GuiDraw.drawText(" " + this.display.display.stackSize, 4, 9, 1.0f, textColor, false); GuiDraw.drawItem(item, 26, 4, 16, 16, context.getCurrentDrawingZ()); if (this.display.tradeableNow) { GuiDraw.drawOutline(1, 1, 45, 23, 0x883CFF00, 2); @@ -117,7 +118,7 @@ public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { IKey.str(display.hasCooldown ? this.display.cooldownText : "") .style(IKey.WHITE)); } else if (this.displayType == DisplayType.LIST) { - GuiDraw.drawText("" + this.display.display.stackSize, 6, 4, 0.9f, Config.display_text_color, false); + GuiDraw.drawText("" + this.display.display.stackSize, 6, 4, 0.9f, textColor, false); GuiDraw.drawItem(item, 24, 2, 9, 9, context.getCurrentDrawingZ()); GuiDraw.drawText( this.display.display.getDisplayName() @@ -128,7 +129,7 @@ public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { 36, 4, 0.9f, - Config.display_text_color, + textColor, false); GuiDraw.drawRect( 1, diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 1162c3d..6c91d26 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -23,7 +23,7 @@ vendingmachine.gui.display_mode_list=List vendingmachine.gui.display_sort=Sort: vendingmachine.gui.display_sort_smart=Smart vendingmachine.gui.display_sort_alphabet=Alphabetical Order - +vendingmachine.gui.display_text_color=000000 vendingmachine.gui.cooldown_display.second=s vendingmachine.gui.cooldown_display.minute=m vendingmachine.gui.cooldown_display.hour=h From 39a01d43d2990a67c4acf819163af5771ae18560 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 11 Oct 2025 17:45:02 +0800 Subject: [PATCH 021/160] Removed flavortext labels from trades. --- .../blocks/gui/MTEVendingMachineGui.java | 3 --- .../vendingmachine/blocks/gui/TradeItemDisplay.java | 10 ++-------- .../network/handlers/NetTradeDisplaySync.java | 1 - .../com/cubefury/vendingmachine/trade/TradeGroup.java | 7 ------- 4 files changed, 2 insertions(+), 19 deletions(-) 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 a3d3f66..50e4ad6 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -464,9 +464,6 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { } builder.emptyLine(); - builder.addLine( - IKey.str(cur.label) - .style(IKey.GRAY)); builder.addLine( IKey.str(Translator.translate("vendingmachine.gui.trade_hint")) .style(IKey.GRAY)); diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java index 1845e84..6e5e68b 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java @@ -18,7 +18,6 @@ public class TradeItemDisplay { public ItemStack display; public UUID tgID; public int tradeGroupOrder; - public String label; public long cooldown; public String cooldownText; public boolean hasCooldown; @@ -26,15 +25,14 @@ public class TradeItemDisplay { public boolean tradeableNow; public TradeItemDisplay(List fromCurrency, List fromItems, List toItems, - ItemStack display, UUID tgID, int tradeGroupOrder, String label, long cooldown, String cooldownText, - boolean hasCooldown, boolean enabled, boolean tradeableNow) { + ItemStack display, UUID tgID, int tradeGroupOrder, long cooldown, String cooldownText, boolean hasCooldown, + boolean enabled, boolean tradeableNow) { this.fromCurrency = fromCurrency; this.fromItems = fromItems; this.toItems = toItems; this.display = display; this.tgID = tgID; this.tradeGroupOrder = tradeGroupOrder; - this.label = label; this.cooldown = cooldown; this.cooldownText = cooldownText; this.hasCooldown = hasCooldown; @@ -43,10 +41,6 @@ public TradeItemDisplay(List fromCurrency, List from } public boolean satisfiesSearch(ItemFilter filter, String searchStringNoCase) { - if (filter == null) { - return this.label.toLowerCase() - .contains(searchStringNoCase); - } return filter.matches(this.display) || this.toItems.stream() .anyMatch(bis -> filter.matches(bis.getBaseStack())) || this.fromItems.stream() 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 a399f08..eb1210a 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -89,7 +89,6 @@ public TradeItemDisplay formatItemDisplay() { t.displayItem == null ? t.displayItem.convertToItemStack() : displayItem, this.tgID, this.tradeGroupOrder, - tg.getLabel(), this.cooldown, convertCooldownText(this.cooldown), this.cooldown > 0, diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index 1436b1d..f45b017 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -28,7 +28,6 @@ public class TradeGroup { private final List trades = new ArrayList<>(); public int cooldown = -1; public int maxTrades = -1; - public String label = ""; private TradeCategory category = TradeCategory.UNKNOWN; private String original_category_str = ""; private final Set requirementSet = new HashSet<>(); @@ -193,7 +192,6 @@ public boolean readFromNBT(NBTTagCompound nbt) { } this.cooldown = nbt.getInteger("cooldown"); this.maxTrades = nbt.getInteger("maxTrades"); - this.label = nbt.getString("label"); NBTTagList tradeList = nbt.getTagList("trades", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < tradeList.tagCount(); i++) { NBTTagCompound trade = tradeList.getCompoundTagAt(i); @@ -217,7 +215,6 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { nbt.setTag("id", NBTConverter.UuidValueType.TRADEGROUP.writeId(this.id)); nbt.setInteger("cooldown", this.cooldown); nbt.setInteger("maxTrades", this.maxTrades); - nbt.setString("label", this.label); nbt.setString("category", this.category.getKey()); NBTTagList tList = new NBTTagList(); for (Trade t : trades) { @@ -232,10 +229,6 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { return nbt; } - public String getLabel() { - return this.label; - } - @Optional.Method(modid = "betterquesting") public void removeAllSatisfiedBqConditions(UUID player) { synchronized (tradeState) { From 0c3f7e6ff49dcee2529311be3b4b1f7279f93ed3 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 11 Oct 2025 18:03:40 +0800 Subject: [PATCH 022/160] Fixed item display override --- .../network/handlers/NetTradeDisplaySync.java | 3 +-- .../com/cubefury/vendingmachine/trade/Trade.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) 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 eb1210a..fe339ba 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -80,8 +80,7 @@ public TradeItemDisplay formatItemDisplay() { TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(this.tgID); Trade t = tg.getTrades() .get(this.tradeGroupOrder); - ItemStack displayItem = t.toItems.get(0) - .convertToItemStack(); + ItemStack displayItem = t.getDisplayItem(); return new TradeItemDisplay( t.fromCurrency, t.fromItems, diff --git a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java index a0f9a7c..e6d0e26 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; +import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.common.util.Constants; @@ -56,6 +57,8 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { } public void readFromNBT(NBTTagCompound nbt) { + displayItem = BigItemStack.loadItemStackFromNBT(nbt.getCompoundTag("displayItem")); + fromCurrency.clear(); fromItems.clear(); toItems.clear(); @@ -76,9 +79,18 @@ public void readFromNBT(NBTTagCompound nbt) { } } + public ItemStack getDisplayItem() { + return this.displayItem.getBaseStack() + .isItemEqual(new ItemStack(ItemPlaceholder.placeholder)) + ? this.toItems.get(0) + .convertToItemStack() + : this.displayItem.getBaseStack(); + } + @Optional.Method(modid = "betterquesting") @SideOnly(Side.CLIENT) public IGuiPanel getTradeGui(IGuiRect rect) { return new PanelQBTrade(rect, this); } + } From 698ebb4f44de66d1ab6cfb567817e344e4dce222 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 11 Oct 2025 18:57:50 +0800 Subject: [PATCH 023/160] Regularized save file format by sorting the names of NBT tags within compound before writing --- .../com/cubefury/vendingmachine/Config.java | 9 ++++++++ .../vendingmachine/trade/TradeDatabase.java | 3 ++- .../vendingmachine/util/NBTConverter.java | 22 ++++++++++--------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/Config.java b/src/main/java/com/cubefury/vendingmachine/Config.java index 3e4af3e..a208507 100644 --- a/src/main/java/com/cubefury/vendingmachine/Config.java +++ b/src/main/java/com/cubefury/vendingmachine/Config.java @@ -10,6 +10,7 @@ public class Config { private static final String CONFIG_CATEGORY_VM = "Vending Machine Settings"; + private static final String CONFIG_CATEGORY_DEVELOPER = "Developer Settings"; public static String data_dir = "vendingmachine"; public static String config_dir = "config/vendingmachine"; @@ -18,6 +19,7 @@ public class Config { public static int dispense_amount = 16; public static DisplayType display_type = DisplayType.TILE; public static MTEVendingMachineGui.SortMode sort_mode = MTEVendingMachineGui.SortMode.SMART; + public static boolean forceRewriteDatabase = false; public static File worldDir = null; @@ -42,6 +44,13 @@ public static void init(File configFile) { Integer.MAX_VALUE, "Number of items per dispense cycle"); + configuration.addCustomCategoryComment(CONFIG_CATEGORY_DEVELOPER, "Developer Settings"); + forceRewriteDatabase = configuration.getBoolean( + "force_rewrite_database", + CONFIG_CATEGORY_DEVELOPER, + forceRewriteDatabase, + "Force rewrite database on load, for add/remove trades or change of format"); + try { display_type = DisplayType.valueOf( configuration.getString( diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index f1db10f..ebdf6a7 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -13,6 +13,7 @@ import net.minecraft.nbt.NBTTagList; import net.minecraftforge.common.util.Constants; +import com.cubefury.vendingmachine.Config; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.integration.betterquesting.BqAdapter; import com.cubefury.vendingmachine.integration.nei.NeiRecipeCache; @@ -94,7 +95,7 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge) { tradeGroups.put(tg.getId(), tg); } - if (newMetadataCount > 0) { + if (Config.forceRewriteDatabase || newMetadataCount > 0) { VendingMachine.LOG.info("Appended metadata to {} new trades", newMetadataCount); DirtyDbMarker.markDirty(); } diff --git a/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java b/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java index d09ef91..660194f 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java +++ b/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Map.Entry; import java.util.Optional; -import java.util.Set; import java.util.TreeSet; import java.util.UUID; import java.util.stream.Collectors; @@ -194,17 +193,20 @@ else if (value instanceof NBTTagByteArray) { public static void NBTtoJSON_Compound(NBTTagCompound parent, JsonWriter out, boolean format) throws IOException { out.beginObject(); - if (parent != null) for (String key : (Set) parent.func_150296_c()) { - NBTBase tag = parent.getTag(key); + if (parent != null) for (String key : parent.func_150296_c() + .stream() + .sorted(String::compareTo) + .collect(Collectors.toList())) { + NBTBase tag = parent.getTag(key); - if (format) { - out.name(key + ":" + tag.getId()); - NBTtoJSON_Base(tag, true, out); - } else { - out.name(key); - NBTtoJSON_Base(tag, false, out); + if (format) { + out.name(key + ":" + tag.getId()); + NBTtoJSON_Base(tag, true, out); + } else { + out.name(key); + NBTtoJSON_Base(tag, false, out); + } } - } out.endObject(); } From 2bad5a00907a07b79ddf22a51708f1c5cb1532b0 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 11 Oct 2025 18:58:28 +0800 Subject: [PATCH 024/160] Remove commented out dependency --- dependencies.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 80be233..5b1a875 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,7 +38,6 @@ dependencies { implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") - // implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.24:dev") } From 02df82b3f8798f8d3823c1326b1483e0e330c9de Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 11 Oct 2025 19:12:16 +0800 Subject: [PATCH 025/160] Fixed a bug where connecting to a server would override a player's local trade database. --- .../vendingmachine/network/handlers/NetTradeDbSync.java | 2 +- .../java/com/cubefury/vendingmachine/trade/TradeDatabase.java | 4 ++-- .../java/com/cubefury/vendingmachine/util/JsonHelper.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDbSync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDbSync.java index 1529d58..8ec2b08 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDbSync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDbSync.java @@ -68,6 +68,6 @@ public static void onClient(NBTTagCompound message) { ) { return; } - TradeDatabase.INSTANCE.readFromNBT(message.getCompoundTag("data"), message.getBoolean("merge")); + TradeDatabase.INSTANCE.readFromNBT(message.getCompoundTag("data"), message.getBoolean("merge"), false); } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index ebdf6a7..6c14035 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -72,7 +72,7 @@ public int getTradeCount() { .sum(); } - public void readFromNBT(NBTTagCompound nbt, boolean merge) { + public void readFromNBT(NBTTagCompound nbt, boolean merge, boolean isFileLoad) { if (!merge) { this.clear(); if (VendingMachine.isBqLoaded) { @@ -95,7 +95,7 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge) { tradeGroups.put(tg.getId(), tg); } - if (Config.forceRewriteDatabase || newMetadataCount > 0) { + if (isFileLoad && (Config.forceRewriteDatabase || newMetadataCount > 0)) { VendingMachine.LOG.info("Appended metadata to {} new trades", newMetadataCount); DirtyDbMarker.markDirty(); } diff --git a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java index 0dc336f..de316a9 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java +++ b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java @@ -55,7 +55,7 @@ public static void populateTradeDatabaseFromFile(File file) { Function readNbt = f -> NBTConverter .JSONtoNBT_Object(FileIO.ReadFromFile(f), new NBTTagCompound(), true); - db.readFromNBT(readNbt.apply(file), false); + db.readFromNBT(readNbt.apply(file), false, true); } public static void populateTradeStateFromFiles(List files) { From 35b153f08af429eb67e0993cf867eace14c81453 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 04:05:29 +0800 Subject: [PATCH 026/160] [V2 Fix] Fixed a bug where the coins display in GUI would not update correctly. --- .../blocks/gui/MTEVendingMachineGui.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) 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 a3d3f66..6014419 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -4,6 +4,7 @@ import static com.cubefury.vendingmachine.gui.GuiTextures.SORT_SMART; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -572,8 +573,10 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { .left(3); Flow coinColumn = new Column().width(COIN_COLUMN_WIDTH); int coinCount = 0; + + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()); Map currentAmounts = TradeManager.INSTANCE.playerCurrency - .getOrDefault(NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()), new HashMap<>()); + .getOrDefault(playerId, Collections.EMPTY_MAP); for (CurrencyItem.CurrencyType type : CurrencyItem.CurrencyType.values()) { coinColumn.child( new Row().child( @@ -592,15 +595,17 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { .style(IKey.GRAY, IKey.ITALIC)); builder.setAutoUpdate(true); })) - .child( - IKey.dynamic( - () -> getReadableStringFromCoinAmount( - currentAmounts.get(type) == null ? 0 : currentAmounts.get(type))) - .scale(0.8f) - .asWidget() - .top(3) - .left(14) - .width(21)) + .child(IKey.dynamic(() -> { + Map currencyMap = TradeManager.INSTANCE.playerCurrency + .getOrDefault(playerId, Collections.EMPTY_MAP); + return getReadableStringFromCoinAmount( + currencyMap.get(type) == null ? 0 : currencyMap.get(type)); + }) + .scale(0.8f) + .asWidget() + .top(3) + .left(14) + .width(21)) .height(14)); if (++coinCount % COIN_COLUMN_ROW_COUNT == 0) { parent.child(coinColumn.left(3 + COIN_COLUMN_WIDTH * (coinCount / COIN_COLUMN_ROW_COUNT - 1))); From 19fd3c252c9bc44857cc4a78af0e99245e97c075 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 19:31:26 +0800 Subject: [PATCH 027/160] Adapt to MUI2 update --- dependencies.gradle | 4 ++-- .../blocks/gui/MTEVendingMachineGui.java | 4 ++-- .../vendingmachine/blocks/gui/SearchBar.java | 10 +++++++--- .../blocks/gui/TradeItemDisplayWidget.java | 4 ++-- .../com/cubefury/vendingmachine/gui/GuiTextures.java | 12 ++++++++++-- .../cubefury/vendingmachine/gui/WidgetThemes.java | 8 +++++--- 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 80be233..f9b2b97 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -37,10 +37,10 @@ dependencies { implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.9-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.1-1.7.10:dev") // implementation("com.github.GTNewHorizons:ModularUI2:2.2.20-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.24:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.30:dev") } // deps may transitively add Baubles, so we replace it 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 6014419..ca01956 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -280,7 +280,7 @@ private SearchBar createSearchBar() { return new SearchBar(this).width(162) .left(3) .top(5) - .height(10); + .height(14); } // Eject code is in GUI instead of MTE since the syncers are per-gui instance @@ -346,7 +346,7 @@ private void doEjectItems() { } private IWidget createIOColumn() { - return new ParentWidget<>().excludeAreaInNEI() + return new ParentWidget<>().excludeAreaInRecipeViewer() .width(50) .height(178) .right(-48) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java index 72de631..2d4ba8a 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java @@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; -import com.cleanroommc.modularui.theme.WidgetTextFieldTheme; +import com.cleanroommc.modularui.theme.TextFieldTheme; import com.cleanroommc.modularui.widgets.textfield.BaseTextFieldWidget; import com.cubefury.vendingmachine.gui.GuiTextures; import com.cubefury.vendingmachine.util.Translator; @@ -21,6 +21,7 @@ public SearchBar(MTEVendingMachineGui gui) { this.gui = gui; background(GuiTextures.TEXT_FIELD_BACKGROUND); + hoverBackground(GuiTextures.TEXT_FIELD_BACKGROUND); setText(""); this.previousText = ""; hintText(Translator.translate("vendingmachine.gui.search")); @@ -69,9 +70,12 @@ public String getText() { } @Override - protected void setupDrawText(ModularGuiContext context, WidgetTextFieldTheme widgetTheme) { + protected void setupDrawText(ModularGuiContext context, TextFieldTheme widgetTheme) { this.renderer.setSimulate(false); - this.renderer.setPos(getArea().getPadding().left, 0); + this.renderer.setPos( + getArea().getPadding() + .getLeft(), + 0); this.renderer.setScale(this.scale); this.renderer.setAlignment(this.textAlignment, -1, getArea().height); } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index ebb0549..88500bc 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -15,7 +15,7 @@ import com.cleanroommc.modularui.drawable.Icon; import com.cleanroommc.modularui.drawable.UITexture; import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; -import com.cleanroommc.modularui.theme.WidgetTheme; +import com.cleanroommc.modularui.theme.WidgetThemeEntry; import com.cleanroommc.modularui.utils.Platform; import com.cleanroommc.modularui.value.sync.GenericSyncValue; import com.cleanroommc.modularui.value.sync.SyncHandler; @@ -94,7 +94,7 @@ public TradeItemDisplay getDisplay() { } @Override - public void draw(ModularGuiContext context, WidgetTheme widgetTheme) { + public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { int textColor = Translator.getColor("vendingmachine.gui.display_text_color"); ItemStack item = value.getValue(); if (!Platform.isStackEmpty(item)) { diff --git a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java index 3de4571..ba50881 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java @@ -1,6 +1,9 @@ package com.cubefury.vendingmachine.gui; +import net.minecraft.util.ResourceLocation; + import com.cleanroommc.modularui.api.GuiAxis; +import com.cleanroommc.modularui.drawable.ColorType; import com.cleanroommc.modularui.drawable.TabTexture; import com.cleanroommc.modularui.drawable.UITexture; import com.cubefury.vendingmachine.VendingMachine; @@ -116,6 +119,11 @@ public final class GuiTextures { .name("coin_eject") .build(); - public static final TabTexture TAB_LEFT = TabTexture - .of(UITexture.fullImage(VendingMachine.MODID, "gui/tabs_left", true), GuiAxis.X, false, 32, 28, 4); + public static final TabTexture TAB_LEFT = TabTexture.of( + UITexture.fullImage(new ResourceLocation(VendingMachine.MODID, "gui/tabs_left"), ColorType.DEFAULT), + GuiAxis.X, + false, + 32, + 28, + 4); } diff --git a/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java b/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java index caf00cf..2fe524f 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java @@ -11,13 +11,15 @@ public final class WidgetThemes { public static void register() { IThemeApi themeApi = IThemeApi.get(); - registerThemedTexture(themeApi, BACKGROUND_SIDEPANEL, GuiTextures.SIDE_PANEL_BACKGROUND); + registerThemedTexture(themeApi, BACKGROUND_SIDEPANEL, GuiTextures.SIDE_PANEL_BACKGROUND, 0, 0); } - private static void registerThemedTexture(IThemeApi themeApi, String textureThemeId, UITexture background) { + private static void registerThemedTexture(IThemeApi themeApi, String textureThemeId, UITexture background, + int defaultWidth, int defaultHeight) { themeApi.registerWidgetTheme( textureThemeId, - new WidgetTheme(background, null, Color.WHITE.main, 0xFF404040, false), + new WidgetTheme(defaultWidth, defaultHeight, background, Color.WHITE.main, 0xFF404040, false, 0), + new WidgetTheme(defaultWidth, defaultHeight, background, Color.WHITE.main, 0xFF404040, false, 0), WidgetTheme::new); } } From b96f487215a22cf2d05b52e7d24a2263c0ef6cd0 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 19:54:34 +0800 Subject: [PATCH 028/160] Fix hoverbackground behavior --- .../vendingmachine/blocks/gui/TradeItemDisplayWidget.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 88500bc..44d8576 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -63,12 +63,18 @@ public TradeItemDisplayWidget(TradeItemDisplay display, DisplayType displayType) background( new DynamicDrawable( () -> pressed ? GuiTextures.TILE_TRADE_BUTTON_PRESSED : GuiTextures.TILE_TRADE_BUTTON_UNPRESSED)); + hoverBackground( + new DynamicDrawable( + () -> pressed ? GuiTextures.TILE_TRADE_BUTTON_PRESSED : GuiTextures.TILE_TRADE_BUTTON_UNPRESSED)); } else if (displayType == DisplayType.LIST) { height(MTEVendingMachineGui.LIST_ITEM_HEIGHT); width(MTEVendingMachineGui.LIST_ITEM_WIDTH); background( new DynamicDrawable( () -> pressed ? GuiTextures.LIST_TRADE_BUTTON_PRESSED : GuiTextures.LIST_TRADE_BUTTON_UNPRESSED)); + hoverBackground( + new DynamicDrawable( + () -> pressed ? GuiTextures.TILE_TRADE_BUTTON_PRESSED : GuiTextures.TILE_TRADE_BUTTON_UNPRESSED)); } this.display = display; From c224aca13996fc890a56865b4821e91a2c82dccd Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 19:59:39 +0800 Subject: [PATCH 029/160] Fix hoverbackground behavior for lists --- .../vendingmachine/blocks/gui/TradeItemDisplayWidget.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 44d8576..5817d67 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -74,7 +74,7 @@ public TradeItemDisplayWidget(TradeItemDisplay display, DisplayType displayType) () -> pressed ? GuiTextures.LIST_TRADE_BUTTON_PRESSED : GuiTextures.LIST_TRADE_BUTTON_UNPRESSED)); hoverBackground( new DynamicDrawable( - () -> pressed ? GuiTextures.TILE_TRADE_BUTTON_PRESSED : GuiTextures.TILE_TRADE_BUTTON_UNPRESSED)); + () -> pressed ? GuiTextures.LIST_TRADE_BUTTON_PRESSED : GuiTextures.LIST_TRADE_BUTTON_UNPRESSED)); } this.display = display; From 08b498474c3b4e48df04c31e4b9f413899a06443 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 20:11:53 +0800 Subject: [PATCH 030/160] Fixed persistent tooltips onMouseEndHover. --- .../vendingmachine/blocks/gui/TradeItemDisplayWidget.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 5817d67..602f7f1 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -30,8 +30,8 @@ public enum DisplayType { TILE("tile", MODE_TILE), LIST("list", MODE_LIST); - private String type; - private Icon texture; + private final String type; + private final Icon texture; DisplayType(String type, UITexture texture) { this.type = type; @@ -177,6 +177,7 @@ public ItemDisplayWidget item(IValue itemSupplier) { @Override public void onMouseEndHover() { pressed = false; + super.onMouseEndHover(); } @Override From f2eb1363108d5eac590ef028a6f55cc223d8a54b Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 21:02:07 +0800 Subject: [PATCH 031/160] Fix element positioning --- .../blocks/gui/MTEVendingMachineGui.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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 ca01956..8a9176c 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -85,6 +85,7 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { public static final int CUSTOM_UI_HEIGHT = 320; // Trade Item Display + public static final int TRADE_ROW_WIDTH = 154; public static final int TILE_ITEMS_PER_ROW = 3; public static final int TILE_ITEM_HEIGHT = 25; public static final int TILE_ITEM_WIDTH = 47; @@ -484,14 +485,14 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t .height(146); for (TradeCategory category : this.tradeCategories) { ListWidget tradeList = new ListWidget<>().debugName("items") - .width(156) + .width(161) .top(1) .height(144) .collapseDisabledChild(true); tradeList.child(new Row().height(2)); // Higher first row top margin - Flow row = new TradeRow().height(TILE_ITEM_HEIGHT +2).left(2); + Flow row = new TradeRow().height(TILE_ITEM_HEIGHT +2).width(TRADE_ROW_WIDTH).marginLeft(2); // Tiles Display for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { @@ -515,7 +516,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t if (i % TILE_ITEMS_PER_ROW == TILE_ITEMS_PER_ROW - 1) { tradeList.child(row); - row = new TradeRow().height(TILE_ITEM_HEIGHT +2).left(2); + row = new TradeRow().height(TILE_ITEM_HEIGHT +2).width(TRADE_ROW_WIDTH).marginLeft(2); } } if (row.hasChildren()) { @@ -523,7 +524,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t } // List Display - row = new TradeRow().height(LIST_ITEM_HEIGHT).left(2); + row = new TradeRow().height(LIST_ITEM_HEIGHT).width(TRADE_ROW_WIDTH).marginLeft(2); for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { int index = i; displayedTradesList.get(category).get(i).setRootPanel(rootPanel); @@ -542,7 +543,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t return displayType == display.displayType && display.getDisplay() != null; })); tradeList.child(row); - row = new TradeRow().height(LIST_ITEM_HEIGHT).left(2); + row = new TradeRow().height(LIST_ITEM_HEIGHT).width(TRADE_ROW_WIDTH).marginLeft(2); } tradeList.child(new Row().height(2)); // bottom padding for last row From 9b87a8c59d86919e5b2cffb9f051f36b9de45386 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 21:05:25 +0800 Subject: [PATCH 032/160] Remove color-correction work around for ListWidget elements --- .../cubefury/vendingmachine/gui/GuiTextures.java | 12 ++++++++---- ...list_trade_button_pressed_color_corrected.png | Bin 3210 -> 0 bytes ...st_trade_button_unpressed_color_corrected.png | Bin 3211 -> 0 bytes .../trade_button_pressed_color_corrected.png | Bin 3261 -> 0 bytes .../trade_button_unpressed_color_corrected.png | Bin 3280 -> 0 bytes 5 files changed, 8 insertions(+), 4 deletions(-) delete mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed_color_corrected.png delete mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed_color_corrected.png delete mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_pressed_color_corrected.png delete mode 100644 src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_unpressed_color_corrected.png diff --git a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java index ba50881..2a9c414 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java @@ -50,28 +50,32 @@ public final class GuiTextures { // TODO: Restore canApplyTheme to trade button textures after scrolling texture bug is fixed in MUI2 public static final UITexture TILE_TRADE_BUTTON_UNPRESSED = UITexture.builder() - .location(VendingMachine.MODID, "gui/background/trade_button_unpressed_color_corrected") + .location(VendingMachine.MODID, "gui/background/trade_button_unpressed") + .canApplyTheme() .imageSize(195, 136) .adaptable(4) .name("trade_button_unpressed") .build(); public static final UITexture TILE_TRADE_BUTTON_PRESSED = UITexture.builder() - .location(VendingMachine.MODID, "gui/background/trade_button_pressed_color_corrected") + .location(VendingMachine.MODID, "gui/background/trade_button_pressed") + .canApplyTheme() .imageSize(195, 136) .adaptable(4) .name("trade_button_pressed") .build(); public static final UITexture LIST_TRADE_BUTTON_UNPRESSED = UITexture.builder() - .location(VendingMachine.MODID, "gui/background/list_trade_button_unpressed_color_corrected") + .location(VendingMachine.MODID, "gui/background/list_trade_button_unpressed") + .canApplyTheme() .imageSize(195, 136) .adaptable(2) .name("list_trade_button_unpressed") .build(); public static final UITexture LIST_TRADE_BUTTON_PRESSED = UITexture.builder() - .location(VendingMachine.MODID, "gui/background/list_trade_button_pressed_color_corrected") + .location(VendingMachine.MODID, "gui/background/list_trade_button_pressed") + .canApplyTheme() .imageSize(195, 136) .adaptable(2) .name("list_trade_button_pressed") diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed_color_corrected.png b/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed_color_corrected.png deleted file mode 100644 index 994c3d1ba371eff912417a0ceaa616768a1ddb8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3210 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 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed_color_corrected.png b/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed_color_corrected.png deleted file mode 100644 index e931d75bdf6a09fa21f0cb1fa1657e1299308aaf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3211 zcmd5;=|9wq7ycrI>{}DrvP@ZL(%7@iU~Jh9LZb<}VJ6144zjOvL&?5mE3PComPTZc zG4?2B>mssmV^BZ$Pq^=XFV6Fv=Q+>kyg6@9lGQC^PWDUe003~BAQ3ia+<8`s=UL9s zdF~GL8J+Xex6lWGy1zJ1+|M+-nl~J76<}j*AYoz%he0%8Fh!^m1OSjp1zACMw$nlh zRI(b`DuXBa$?${wHjGG4GBRE18ib9#8F^=xjQi} z#S6{KaA6Bz@&V>>_4NiqG$Y0w#_*|BpB#RgFu8?G;^_F=m~LtZ@Vn?qvy&7Au*yzd z-l0vqfQ0+ibx`>-B+LHnx2hIHDyBnHPSH?@%zzz*+u;W}9^4wc&{%EIK)}#~$JX~5 zxy3XMzP8kKG)Q>)JgphpCX0!|o5bt&V87Ra!f(Ls5GcINfMGvkjuWZtbxFX?q!l^cG zUpN1858lmG&%i_AZfbs>p%sX(zM%!&(S@a=1e!SOuRt*&-V^DzMCB)jh=B@o3G=MR z+kO0r%sB?}dbFZk8h7Wfvgzimq|Y?o;VehSa>+}25n=%N8m|Of*gg5-O#(-cG1Czx zWh5uN;Fucyi-2k}|J5fX9ZAF(BcM%u)+P`rd2(W6(;`nb8p*un*i=P zCPsa5;<<-t$Xv9*V+MqTus~E}@x>?6HE6jPEP=(msxdI!Mf@YooT@sj(xUzV7i5Vk!K6Zn7bDF@Wd-XQ>p}G*V?>QOP*19RMV;f{nvA3sObtGDr7zQh61jrSU&2W4FLy%xsB_3-7gAxu1bXJ-1)i+g*J z3jB@0(?FS){g#-P>!CfN)}e8s>!F8xY;=WF>C?+}GToL%lSPt+nWct>#JL@>&?(UA z8h;vJo0gh(Hx+g<5TpZjxXz_Aq~>>{?STR8p_-HDDB7PQfcXfuxc=2Qbov6UUd;?r z4H1DRP%aNLFSSw<6o-Xw2^plYq==aFjb-L^`gjnXM-^ifITTwJikv`>-M4+~S4s5y zzSsi4ulEVP@pt*}+uk3;>{i$0D1Lg|bMV<^$7Qy;dihT(!OzRDm-Gb_G*rd!&M^mB=J9H#*NOa%9bxai@i;q{Wk52>A5 zaRhN98#hNSTjWJ|erukQ_fakA{^%^`S}C&BfYc@;2VwF&v{bN^|9M{No!;QyC%s5a z&0SQFTk=>Ue^+2HX0dcJZ=q6{t}xS#)9$!gqCQWTS~LtvQBs(6%x|O7__}5CWsLbo zk|0TnNt+ra`7A?wqfzCJW|d7o8%i7eg{)XsY{uqCStztg z-?3{Kvg0VMq*qRsx835f_)>ImRY#Vr!}KgY`=K3@w}R~$+IW2znovJjpIl!ykpFDm z1t!DJcf$ido${u&TXmW`9@T|-;|9%L%(Bhgl~vO`L>BrNs$kL0(>oReayx|G_im4z zJ6uO@7vFyU7L6}o{z$hUt}3q%MXl8;IqS6bU@4CpV;j96M1mWX6qLi8l{{T7(;Y@~ zpV#e2tldr#Og8LRgEjfQ_>%Y;Jf+^`y-`tRA#N5dBWzY zXz+MFSmHx<7<8DQT>COZx(r4sQI*BNh`k{Puwsn+iO;m2{d{NTj!w*)uJ~kq3`KKET!?uglvMw zu^7xq?I4muZ)r9uecAA%Gh#mC$D>3h0)_*7#n zNzcR>6QmQwBJ*hL`~yA{bJ_wLvs#O{?Z#=WuxIb~fpTJVXcw4L|KFHnQ z1Au$@1cU@g*y024d1EE)uvnjt%K2~rV0dPN(6XaeR!*?Wcl+W(we?vFd*OSQLnU}M;Xv?kr>UdpKnQEyEnZbUV$U`Tc zhUbz#rCgk&UVQ7jgoA9O-(BE==;fQ7K^MTwg!otehemf*|39Sv)9U}D@R49=L`czT lxHFk8>xk&S&qL#G1OA@!G2ei7TtB-cU}AU+@yY-l{Xc^Ew6OpH diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_pressed_color_corrected.png b/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_pressed_color_corrected.png deleted file mode 100644 index 1c15f01d60f3eb27b5e2c35f4a16befc66aab7c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3261 zcmds(={wX77sr1iTNtv8+mu^miDbr-NTxzUG-I-x$eL{!%Vf-0vyP#WY%!JfW<-{; zG|G}COUbR0ts;Ywtdl+D@%#=da005hrUcGtf zorjS5c@Nd``)!^>89NjAaSdPFkm-xdO?@V)v+C@BM` z9yH^&PUSyWS3wvSi2AKhQ)wN0dYZ8_A3f-oxeygdynp=ObCHY_gX!F%%jTU4p1K}ty=-0_jVT>i_|mk+Bt=MD^WsO z(mGYztw4cZOU{K~x9kdbqhe)`7L}+X| zK*2cDuZ{DD=*=P~|HXgPKlQ$rmezfybapzkplu;qZx0;FLCAAL+j5eY-zIwsWN_ny zzS*mosTf{DAhP;cgWv=Gt^?iG>NWf0y~(qy7xd9r>E3Ud&ARAUL~KPKu}OX_mz)NpOzb2%nF%q2x&W5G=Pl?30x5!<=KqAZh7RVfxI{9^c6l`Ff8WXcRl9OXpbQ2H_N-0PiHB$KNuF0FlOm1kQof=}jN zerFy36*4~#(Og-Z6*R#-I1Er7<8Lb#-XTMvmJ+TrrEWD89>Bck4wHURiv3Oxo zHdK07(xj`L)gQRb9v@*3Zl_rEy zy3MZXH_p`%F#J%!w6xDu%Ot&3e5(sF`dmmti_?vVaP<8lr~`D&lTpZUVAwFcJWRa# zZ_wDr=0#b9$iYPKl^kVwkYk4f!`E2gmXn$=eoN6l2`4S=oHD)3U2`SZkGZPAP;`H=ru){E!%vix%Ou(4@^0 z>SJmSl8USwFmhs4#RcRAJX!Wfq{@660z{KuzSSL z4bA=ITZ-$}tk8Vrk33J%ne?9U`4gPmt~tPnd$;Upc{W0=(E*Q%sIOfa_4nB^? z7#j>&i!Ky>O=Fs(Jw850D&Fu}Ae_%W&qWhI-!^)DTxtCL7!o$(FyP?a7SWIVM)k4t z({V$+NNc?8ahX-XevPMxgt6#Ty`k8^$AKS1t_SL|*E`0#a#y~x_2=BC856V3s;r+= zjz7j%l%^$Fw)2~#PTvp%En|`0ogMB^dWfj{vKMm!|GL6G;n{Y@BmDvukOjN-u#D!o zX4RJb?H{|VkuM`$Cn2rj5htsL9Q!b1Q+#{Pdz;&cUn3mU+QB72{QF5u$m+SlbLu)Z zI%F{k$dJUk(&z=I!nOf9fUI6}(OUDIX1xX;)~{W84(pM{dA3nem82RU(s@z7Mzl~A zELvCb&345JA>$+JaO^_;HLn}Pc@=(;VWsB?aYg8xR6Xc@s&GmG<Rv3;>L z1(-sDVuRB3!{Q7S$0IDc`Kd%!W@Y9*>$suVq4aaK`W7Fp2waqrUS_LOi`5m#zQxAT zy9tP*Dks9e&12#+w$62FH7F*oq@%1Tq>cT@Y4@^qx7|c}aFy?K+h-GK z1R*BUWwl_sJ^T1!y)8Cn^+jY3&w!ihJB8zqv zraj&f94BpFpvMKi6mBkV=2Ew*=>w|+_pDTrcL`&m4UxF@{q#@1WfcRxPgO3M>(Zh_ zr)~{2jjff>mBG85q!y?@qXL6IzxjdyA@*~c;Z9A9Q9EwcRx3@ap?1jI4Nat<$EO{8 z?!H@Cij<7>zihuZIE)*cjOzS(ZSKYb&FRQHz5!u9A!p_+Y2lZD^_P*A%4RKf2~9jf zH#lqtw!1vjQW6ed@%ow{T{AED+jUC5++;Q_OJ-!BzU96^p6$&=k9=r7ZGe(Vt?hn# zkoo6R5@)Y$rfgRHnfU#TI~iqVU&{h6VfL|m#Gh+B^RfB=L{~)>?y_FpmX4mMIcRJB zd3X>!HNvv{RZVSn-h3H89KFe*&FHL!B;aNzWg>gRMs_bP?srA7`4*EXX{3{{E)kXit0%VN*LHQdRb&p|%%g#(4j}*_DE41KAHPNI9S%?6jqUMPxI1`)Yp^F^9Ne5TB0WphqKb?dRjH!oG*uq;_6^< h&h><9yhiu7$b7`P4vD7uDClRvEg){s%~7?P&l2 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_unpressed_color_corrected.png b/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_unpressed_color_corrected.png deleted file mode 100644 index 13c9e0107d5860a4bad8cc3bcaff39113a2bc9bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3280 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 From 8dfe321e8a97be28167f851b2c8297cf19c33253 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 21:50:09 +0800 Subject: [PATCH 033/160] [Crashing] Address Review Comments --- .../vendingmachine/VendingMachine.java | 4 --- .../vendingmachine/blocks/gui/SearchBar.java | 6 ++--- .../vendingmachine/gui/WidgetThemes.java | 26 +++++++++---------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java index 7ef5787..6bac1b5 100644 --- a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java @@ -3,7 +3,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.cubefury.vendingmachine.gui.WidgetThemes; import com.cubefury.vendingmachine.items.VMItems; import com.cubefury.vendingmachine.network.PacketTypeRegistry; import com.cubefury.vendingmachine.network.SerializedPacket; @@ -66,9 +65,6 @@ public void preInit(FMLPreInitializationEvent event) { network.registerMessage(SerializedPacket.HandleClient.class, SerializedPacket.class, 0, Side.CLIENT); network.registerMessage(SerializedPacket.HandleServer.class, SerializedPacket.class, 0, Side.SERVER); - // ModularUI - WidgetThemes.register(); - } @Mod.EventHandler diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java index 2d4ba8a..b611874 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java @@ -7,7 +7,7 @@ import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; import com.cleanroommc.modularui.theme.TextFieldTheme; import com.cleanroommc.modularui.widgets.textfield.BaseTextFieldWidget; -import com.cubefury.vendingmachine.gui.GuiTextures; +import com.cubefury.vendingmachine.gui.WidgetThemes; import com.cubefury.vendingmachine.util.Translator; public class SearchBar extends BaseTextFieldWidget { @@ -19,9 +19,7 @@ public SearchBar(MTEVendingMachineGui gui) { super(); this.gui = gui; - - background(GuiTextures.TEXT_FIELD_BACKGROUND); - hoverBackground(GuiTextures.TEXT_FIELD_BACKGROUND); + widgetTheme(WidgetThemes.BACKGROUND_SEARCH_BAR); setText(""); this.previousText = ""; hintText(Translator.translate("vendingmachine.gui.search")); diff --git a/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java b/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java index 2fe524f..ebad55b 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java @@ -1,25 +1,23 @@ package com.cubefury.vendingmachine.gui; import com.cleanroommc.modularui.api.IThemeApi; -import com.cleanroommc.modularui.drawable.UITexture; import com.cleanroommc.modularui.theme.WidgetTheme; +import com.cleanroommc.modularui.theme.WidgetThemeKey; import com.cleanroommc.modularui.utils.Color; public final class WidgetThemes { - public static final String BACKGROUND_SIDEPANEL = "background_side_panel"; + private static final IThemeApi themeApi = IThemeApi.get(); - public static void register() { - IThemeApi themeApi = IThemeApi.get(); - registerThemedTexture(themeApi, BACKGROUND_SIDEPANEL, GuiTextures.SIDE_PANEL_BACKGROUND, 0, 0); - } + public static final WidgetThemeKey BACKGROUND_SIDEPANEL = themeApi + .widgetThemeKeyBuilder("background_side_panel", WidgetTheme.class) + .defaultTheme(new WidgetTheme(0, 0, GuiTextures.SIDE_PANEL_BACKGROUND, Color.WHITE.main, 0xFF404040, false, 0)) + .defaultHoverTheme(null) + .register(); - private static void registerThemedTexture(IThemeApi themeApi, String textureThemeId, UITexture background, - int defaultWidth, int defaultHeight) { - themeApi.registerWidgetTheme( - textureThemeId, - new WidgetTheme(defaultWidth, defaultHeight, background, Color.WHITE.main, 0xFF404040, false, 0), - new WidgetTheme(defaultWidth, defaultHeight, background, Color.WHITE.main, 0xFF404040, false, 0), - WidgetTheme::new); - } + public static final WidgetThemeKey BACKGROUND_SEARCH_BAR = themeApi + .widgetThemeKeyBuilder("background_search_bar", WidgetTheme.class) + .defaultTheme(new WidgetTheme(0, 0, GuiTextures.TEXT_FIELD_BACKGROUND, Color.WHITE.main, 0xFF404040, false, 0)) + .defaultHoverTheme(null) + .register(); } From c948122513dbdab94e65f92c5d1e5f4457a69571 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 12 Oct 2025 22:39:22 +0800 Subject: [PATCH 034/160] [Working] Address Review Comments --- .../vendingmachine/VendingMachine.java | 4 +++ .../blocks/gui/TradeItemDisplayWidget.java | 8 ++---- .../vendingmachine/gui/WidgetThemes.java | 25 ++++++++++++++++--- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java index 6bac1b5..4e9ca12 100644 --- a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java @@ -3,6 +3,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.cubefury.vendingmachine.gui.WidgetThemes; import com.cubefury.vendingmachine.items.VMItems; import com.cubefury.vendingmachine.network.PacketTypeRegistry; import com.cubefury.vendingmachine.network.SerializedPacket; @@ -61,6 +62,9 @@ public void preInit(FMLPreInitializationEvent event) { proxy.registerHandlers(); PacketTypeRegistry.INSTANCE.init(); + // MUI2 + WidgetThemes.init(); + // Register network handlers network.registerMessage(SerializedPacket.HandleClient.class, SerializedPacket.class, 0, Side.CLIENT); network.registerMessage(SerializedPacket.HandleServer.class, SerializedPacket.class, 0, Side.SERVER); diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 602f7f1..fccdf13 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -21,6 +21,7 @@ import com.cleanroommc.modularui.value.sync.SyncHandler; import com.cleanroommc.modularui.widgets.ItemDisplayWidget; import com.cubefury.vendingmachine.gui.GuiTextures; +import com.cubefury.vendingmachine.gui.WidgetThemes; import com.cubefury.vendingmachine.util.Translator; public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { @@ -57,24 +58,19 @@ public Icon getTexture() { public TradeItemDisplayWidget(TradeItemDisplay display, DisplayType displayType) { this.displayType = displayType; + widgetTheme(WidgetThemes.THEME_TRADE_BUTTON); if (displayType == DisplayType.TILE) { height(MTEVendingMachineGui.TILE_ITEM_HEIGHT); width(MTEVendingMachineGui.TILE_ITEM_WIDTH); background( new DynamicDrawable( () -> pressed ? GuiTextures.TILE_TRADE_BUTTON_PRESSED : GuiTextures.TILE_TRADE_BUTTON_UNPRESSED)); - hoverBackground( - new DynamicDrawable( - () -> pressed ? GuiTextures.TILE_TRADE_BUTTON_PRESSED : GuiTextures.TILE_TRADE_BUTTON_UNPRESSED)); } else if (displayType == DisplayType.LIST) { height(MTEVendingMachineGui.LIST_ITEM_HEIGHT); width(MTEVendingMachineGui.LIST_ITEM_WIDTH); background( new DynamicDrawable( () -> pressed ? GuiTextures.LIST_TRADE_BUTTON_PRESSED : GuiTextures.LIST_TRADE_BUTTON_UNPRESSED)); - hoverBackground( - new DynamicDrawable( - () -> pressed ? GuiTextures.LIST_TRADE_BUTTON_PRESSED : GuiTextures.LIST_TRADE_BUTTON_UNPRESSED)); } this.display = display; diff --git a/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java b/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java index ebad55b..3aa882f 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java @@ -1,12 +1,15 @@ package com.cubefury.vendingmachine.gui; import com.cleanroommc.modularui.api.IThemeApi; +import com.cleanroommc.modularui.theme.TextFieldTheme; import com.cleanroommc.modularui.theme.WidgetTheme; import com.cleanroommc.modularui.theme.WidgetThemeKey; import com.cleanroommc.modularui.utils.Color; public final class WidgetThemes { + public static void init() {} + private static final IThemeApi themeApi = IThemeApi.get(); public static final WidgetThemeKey BACKGROUND_SIDEPANEL = themeApi @@ -15,9 +18,25 @@ public final class WidgetThemes { .defaultHoverTheme(null) .register(); - public static final WidgetThemeKey BACKGROUND_SEARCH_BAR = themeApi - .widgetThemeKeyBuilder("background_search_bar", WidgetTheme.class) - .defaultTheme(new WidgetTheme(0, 0, GuiTextures.TEXT_FIELD_BACKGROUND, Color.WHITE.main, 0xFF404040, false, 0)) + public static final WidgetThemeKey BACKGROUND_SEARCH_BAR = themeApi + .widgetThemeKeyBuilder("background_search_bar", TextFieldTheme.class) + .defaultTheme( + new TextFieldTheme( + 0, + 0, + GuiTextures.TEXT_FIELD_BACKGROUND, + Color.WHITE.main, + 0xFF404040, + false, + 0, + 0, + 0xFF404040)) + .defaultHoverTheme(null) + .register(); + + public static final WidgetThemeKey THEME_TRADE_BUTTON = themeApi + .widgetThemeKeyBuilder("background_tile_trade_button", WidgetTheme.class) + .defaultTheme(new WidgetTheme(0, 0, null, Color.WHITE.main, 0xFF404040, false, 0)) .defaultHoverTheme(null) .register(); } From 634b9c5eedf31a600d895afc25429cb40ab57d37 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Sun, 12 Oct 2025 20:11:58 +0200 Subject: [PATCH 035/160] update --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index c85977f..fd08254 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.9-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.11-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.1-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.30:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.32:dev") } // deps may transitively add Baubles, so we replace it From 84a716d4ff8181f2316ae81bb68cddd9a0119dbe Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 13 Oct 2025 02:45:01 +0800 Subject: [PATCH 036/160] Changes: - Replaced method used to get widget width as it no longer exists - Set recipe height and width in handler info --- .../vendingmachine/integration/nei/NEIConfig.java | 4 +++- .../vendingmachine/integration/nei/NeiRecipeHandler.java | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java index 9a16209..730f565 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java @@ -32,7 +32,9 @@ public String getVersion() { @SubscribeEvent public void registerHandlerInfo(NEIRegisterHandlerInfosEvent event) { event.registerHandlerInfo( - new HandlerInfo.Builder("vendingmachine", VendingMachine.NAME, VendingMachine.MODID).setMaxRecipesPerPage(3) + new HandlerInfo.Builder("vendingmachine", VendingMachine.NAME, VendingMachine.MODID).setHeight(104) + .setWidth(166) + .setMaxRecipesPerPage(3) .setDisplayStack(VMItems.vendingMachine) .build()); } diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index 3e5f78a..75ef983 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -197,8 +197,8 @@ public boolean isMouseOverBqCondition(int recipeIndex, int curY, UUID questId, S Point pos = GuiDraw.getMousePosition(); - int guiLeft = (gui.width - gui.getWidgetSize().width) / 2; - int guiTop = 19 + (gui.height - gui.getWidgetSize().height) / 2; + int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; + int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().w) / 2; Point relMousePos = new Point(pos.x - guiLeft - offset.x, pos.y - guiTop - offset.y); Rectangle textArea = new Rectangle(2, curY - GuiDraw.fontRenderer.FONT_HEIGHT, width + 2, height + 1); if (textArea.contains(relMousePos)) { @@ -214,8 +214,8 @@ public boolean isMouseOnLastHovered(GuiRecipe gui, int recipeIndex) { if (lastHoveredTextArea == null || lastHoveredQuestId == null || lastHoveredRecipeIndex != recipeIndex) { return false; } - int guiLeft = (gui.width - gui.getWidgetSize().width) / 2; - int guiTop = 19 + (gui.height - gui.getWidgetSize().height) / 2; + int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; + int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().h) / 2; Point offset = gui.getRecipePosition(recipeIndex); Point pos = GuiDraw.getMousePosition(); From 8d8c2b2245197cf190c78911fbd200f4631f0779 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 13 Oct 2025 14:03:15 +0800 Subject: [PATCH 037/160] Fixed coins not updating in multiplayer. --- .../vendingmachine/handlers/EventHandler.java | 4 ---- .../network/handlers/NetCurrencySync.java | 5 ++--- .../cubefury/vendingmachine/trade/TradeDatabase.java | 6 ++++-- .../cubefury/vendingmachine/trade/TradeManager.java | 11 +++++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index 06febcf..993c95e 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -78,8 +78,6 @@ public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { } NetBulkSync.sendReset(mpPlayer, true, true); - - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(mpPlayer); } @SubscribeEvent @@ -146,7 +144,6 @@ public void onServerTick(TickEvent.ServerTickEvent event) { } private void terminateVendingSession(@Nonnull EntityPlayer player) { - VendingMachine.LOG.info("terminating session for {}", player); if (VendingMachine.proxy.isClient()) { return; } @@ -162,7 +159,6 @@ private void terminateVendingSession(@Nonnull EntityPlayer player) { te instanceof IGregTechTileEntity && ((IGregTechTileEntity) te).getMetaTileEntity() instanceof MTEVendingMachine ) { - VendingMachine.LOG.info("found VM MTE terminating session for {}", player); ((MTEVendingMachine) ((IGregTechTileEntity) te).getMetaTileEntity()).resetCurrentUser(player); SaveLoadHandler.INSTANCE .writeTradeState(Collections.singleton(NameCache.INSTANCE.getUUIDFromPlayer(player))); diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java index 84d8f61..2731569 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java @@ -32,15 +32,14 @@ public static void registerHandler() { } } - // server side code for sending tradegroup data when player opens gui + // server side code for sending currency data when player opens gui public static void syncCurrencyToClient(@Nonnull EntityPlayerMP player) { UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); NBTTagCompound payload = new NBTTagCompound(); payload.setString("dataType", "currencySync"); NBTConverter.UuidValueType.PLAYER.writeId(playerId, payload); - payload.setTag("data", TradeManager.INSTANCE.writeCurrencyToNBT(playerId)); - + payload.setTag("data", TradeManager.INSTANCE.writeCurrencyToNBT(new NBTTagCompound(), playerId)); PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 6c14035..5bf941c 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -9,6 +9,8 @@ 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; @@ -135,7 +137,7 @@ public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean m TradeManager.INSTANCE.populateCurrencyFromNBT(nbt, player, merge); } - public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, UUID player) { + public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, @Nonnull UUID player) { NBTTagList tradeStateList = new NBTTagList(); for (Map.Entry entry : tradeGroups.entrySet()) { TradeHistory history = entry.getValue() @@ -149,7 +151,7 @@ public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, UUID player) { } } nbt.setTag("tradeState", tradeStateList); - nbt.setTag("playerCurrency", TradeManager.INSTANCE.writeCurrencyToNBT(player)); + TradeManager.INSTANCE.writeCurrencyToNBT(nbt, player); return nbt; } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index d527cd6..93c90c8 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -8,6 +8,8 @@ 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; @@ -130,24 +132,25 @@ public void populateCurrencyFromNBT(NBTTagCompound nbt, UUID player, boolean mer this.hasCurrencyUpdate = true; } - public NBTTagList writeCurrencyToNBT(UUID player) { - NBTTagList nbt = new NBTTagList(); + public NBTTagCompound writeCurrencyToNBT(NBTTagCompound nbt, @Nonnull UUID player) { if (this.playerCurrency.get(player) == null) { return nbt; } + NBTTagList nbtCurrencyList = new NBTTagList(); for (Map.Entry entry : this.playerCurrency.get(player) .entrySet()) { NBTTagCompound currencyEntry = new NBTTagCompound(); currencyEntry.setString("currency", entry.getKey().id); currencyEntry.setInteger("amount", entry.getValue()); - nbt.appendTag(currencyEntry); + nbtCurrencyList.appendTag(currencyEntry); } if (this.invalidCurrency.get(player) != null) { for (NBTTagCompound tag : this.invalidCurrency.get(player)) { - nbt.appendTag(tag); + nbtCurrencyList.appendTag(tag); } } + nbt.setTag("playerCurrency", nbtCurrencyList); return nbt; } From 1606b03eee1606af0ae58fea235b993278ce01c2 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 13 Oct 2025 14:08:44 +0800 Subject: [PATCH 038/160] Revert event handler changes - out of scope for PR --- .../com/cubefury/vendingmachine/handlers/EventHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index 993c95e..06febcf 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -78,6 +78,8 @@ public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { } NetBulkSync.sendReset(mpPlayer, true, true); + + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(mpPlayer); } @SubscribeEvent @@ -144,6 +146,7 @@ public void onServerTick(TickEvent.ServerTickEvent event) { } private void terminateVendingSession(@Nonnull EntityPlayer player) { + VendingMachine.LOG.info("terminating session for {}", player); if (VendingMachine.proxy.isClient()) { return; } @@ -159,6 +162,7 @@ private void terminateVendingSession(@Nonnull EntityPlayer player) { te instanceof IGregTechTileEntity && ((IGregTechTileEntity) te).getMetaTileEntity() instanceof MTEVendingMachine ) { + VendingMachine.LOG.info("found VM MTE terminating session for {}", player); ((MTEVendingMachine) ((IGregTechTileEntity) te).getMetaTileEntity()).resetCurrentUser(player); SaveLoadHandler.INSTANCE .writeTradeState(Collections.singleton(NameCache.INSTANCE.getUUIDFromPlayer(player))); From 29c4350741ec866c163d2059181cd9038626fa84 Mon Sep 17 00:00:00 2001 From: Dream Master Date: Mon, 13 Oct 2025 13:22:05 +0200 Subject: [PATCH 039/160] update --- dependencies.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index fd08254..38202ca 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.11-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.14-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.1-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.2-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.32:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.34:dev") } // deps may transitively add Baubles, so we replace it From 6b6a6da74149ffcbce1f22b3ede2b703ab606c8a Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 13 Oct 2025 19:54:10 +0800 Subject: [PATCH 040/160] Changes: - Fixed a bug where tradestate is not written for a player if the server closes while they're still in the GUI. - Fixed Netcode using Betterquesting's packet assembly instead of its own --- .../java/com/cubefury/vendingmachine/VendingMachine.java | 8 ++++++++ .../cubefury/vendingmachine/api/storage/INameCache.java | 2 ++ .../cubefury/vendingmachine/handlers/EventHandler.java | 6 +----- .../cubefury/vendingmachine/network/PacketAssembly.java | 2 +- .../vendingmachine/network/handlers/NetBulkSync.java | 6 +++++- .../com/cubefury/vendingmachine/storage/NameCache.java | 8 ++++++++ 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java index 4e9ca12..89346c5 100644 --- a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java @@ -4,9 +4,11 @@ import org.apache.logging.log4j.Logger; import com.cubefury.vendingmachine.gui.WidgetThemes; +import com.cubefury.vendingmachine.handlers.SaveLoadHandler; import com.cubefury.vendingmachine.items.VMItems; import com.cubefury.vendingmachine.network.PacketTypeRegistry; import com.cubefury.vendingmachine.network.SerializedPacket; +import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.util.ItemPlaceholder; import cpw.mods.fml.common.Loader; @@ -19,6 +21,7 @@ import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.event.FMLServerStartingEvent; import cpw.mods.fml.common.event.FMLServerStoppedEvent; +import cpw.mods.fml.common.event.FMLServerStoppingEvent; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; import cpw.mods.fml.common.registry.GameRegistry; @@ -105,6 +108,11 @@ public void serverStarting(FMLServerStartingEvent event) { proxy.serverStarting(event); } + @Mod.EventHandler + public void serverStopping(FMLServerStoppingEvent event) { + SaveLoadHandler.INSTANCE.writeTradeState(NameCache.INSTANCE.getAllUUIDS()); + } + @Mod.EventHandler public void serverStop(FMLServerStoppedEvent event) {} diff --git a/src/main/java/com/cubefury/vendingmachine/api/storage/INameCache.java b/src/main/java/com/cubefury/vendingmachine/api/storage/INameCache.java index 5aa211c..86be29e 100644 --- a/src/main/java/com/cubefury/vendingmachine/api/storage/INameCache.java +++ b/src/main/java/com/cubefury/vendingmachine/api/storage/INameCache.java @@ -20,6 +20,8 @@ public interface INameCache { List getAllNames(); + List getAllUUIDS(); + /** * Used primarily to know if a user is an OP client side
*/ diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index 06febcf..0420450 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -2,7 +2,6 @@ import java.util.ArrayDeque; import java.util.Collections; -import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; @@ -78,8 +77,6 @@ public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { } NetBulkSync.sendReset(mpPlayer, true, true); - - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(mpPlayer); } @SubscribeEvent @@ -146,7 +143,6 @@ public void onServerTick(TickEvent.ServerTickEvent event) { } private void terminateVendingSession(@Nonnull EntityPlayer player) { - VendingMachine.LOG.info("terminating session for {}", player); if (VendingMachine.proxy.isClient()) { return; } @@ -162,7 +158,7 @@ private void terminateVendingSession(@Nonnull EntityPlayer player) { te instanceof IGregTechTileEntity && ((IGregTechTileEntity) te).getMetaTileEntity() instanceof MTEVendingMachine ) { - VendingMachine.LOG.info("found VM MTE terminating session for {}", player); + VendingMachine.LOG.info("Force terminating VM session for {}", player); ((MTEVendingMachine) ((IGregTechTileEntity) te).getMetaTileEntity()).resetCurrentUser(player); SaveLoadHandler.INSTANCE .writeTradeState(Collections.singleton(NameCache.INSTANCE.getUUIDFromPlayer(player))); diff --git a/src/main/java/com/cubefury/vendingmachine/network/PacketAssembly.java b/src/main/java/com/cubefury/vendingmachine/network/PacketAssembly.java index b9231fc..772e3be 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/PacketAssembly.java +++ b/src/main/java/com/cubefury/vendingmachine/network/PacketAssembly.java @@ -20,7 +20,7 @@ public final class PacketAssembly { - public static final betterquesting.network.PacketAssembly INSTANCE = new betterquesting.network.PacketAssembly(); + public static final PacketAssembly INSTANCE = new PacketAssembly(); // TODO: Allow for simultaneous packet assembly (may not be necessary) // TODO: Implement PROPER thread safety that doesn't cause dirty read/writes 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 2a80342..be1aa33 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetBulkSync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetBulkSync.java @@ -9,10 +9,12 @@ import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.api.network.UnserializedPacket; import com.cubefury.vendingmachine.api.util.Tuple2; +import com.cubefury.vendingmachine.events.MarkDirtyNamesEvent; import com.cubefury.vendingmachine.handlers.SaveLoadHandler; import com.cubefury.vendingmachine.network.PacketSender; import com.cubefury.vendingmachine.network.PacketTypeRegistry; @@ -23,7 +25,7 @@ public class NetBulkSync { - private static final ResourceLocation ID_NAME = new ResourceLocation("vending_machine:main_sync"); + private static final ResourceLocation ID_NAME = new ResourceLocation("vendingmachine:bulk_sync"); public static void registerHandler() { PacketTypeRegistry.INSTANCE.registerServerHandler(ID_NAME, NetBulkSync::onServer); @@ -48,6 +50,8 @@ public static void sendReset(@Nullable EntityPlayerMP player, boolean reset, boo public static void sendSync(@Nonnull EntityPlayerMP player) { NameCache.INSTANCE.updateName(player); + MinecraftForge.EVENT_BUS.post(new MarkDirtyNamesEvent()); + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); NetNameSync.sendNames(new EntityPlayerMP[] { player }, new UUID[] { playerId }, null); diff --git a/src/main/java/com/cubefury/vendingmachine/storage/NameCache.java b/src/main/java/com/cubefury/vendingmachine/storage/NameCache.java index 10b812f..36ec99e 100644 --- a/src/main/java/com/cubefury/vendingmachine/storage/NameCache.java +++ b/src/main/java/com/cubefury/vendingmachine/storage/NameCache.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -145,6 +146,13 @@ public synchronized List getAllNames() { return Collections.unmodifiableList(nameCache); } + @Override + public List getAllUUIDS() { + return cache.keySet() + .stream() + .collect(Collectors.toList()); + } + @Override public UUID getUUIDFromPlayer(EntityPlayer player) { if (player == null) { From 2407461a807a9bb627263c67f9cf2590cd506e68 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 13 Oct 2025 21:06:43 +0800 Subject: [PATCH 041/160] Fix NPE from trade item display load --- .../vendingmachine/network/handlers/NetTradeDisplaySync.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 fe339ba..964bf83 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -6,7 +6,6 @@ import javax.annotation.Nonnull; 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; @@ -80,12 +79,11 @@ public TradeItemDisplay formatItemDisplay() { TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(this.tgID); Trade t = tg.getTrades() .get(this.tradeGroupOrder); - ItemStack displayItem = t.getDisplayItem(); return new TradeItemDisplay( t.fromCurrency, t.fromItems, t.toItems, - t.displayItem == null ? t.displayItem.convertToItemStack() : displayItem, + t.getDisplayItem(), this.tgID, this.tradeGroupOrder, this.cooldown, @@ -148,7 +146,6 @@ public static void syncTradesToClient(@Nonnull EntityPlayerMP player, MTEVending @SideOnly(Side.CLIENT) public static void onClient(NBTTagCompound message) { - // TODO: Load trade view on client List tradeData = TradeManager.INSTANCE.tradeData; tradeData.clear(); From af399f898702c8a09172e80334d35f3210a1f0bb Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 14 Oct 2025 01:00:07 +0800 Subject: [PATCH 042/160] Fix coins going missing on server start in multiplayer. --- .../cubefury/vendingmachine/trade/TradeManager.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 93c90c8..3ae8fe6 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -105,8 +105,14 @@ public List getAvailableTradeGroups(UUID player) { public void populateCurrencyFromNBT(NBTTagCompound nbt, UUID player, boolean merge) { NBTTagList tagList = nbt.getTagList("playerCurrency", Constants.NBT.TAG_COMPOUND); if (!merge) { - this.playerCurrency.clear(); - this.invalidCurrency.clear(); + if (player == null) { + this.playerCurrency.clear(); + this.invalidCurrency.clear(); + } else { + this.playerCurrency.remove(player); + this.invalidCurrency.remove(player); + } + } this.playerCurrency.computeIfAbsent(player, k -> new HashMap<>()); for (int i = 0; i < tagList.tagCount(); i++) { From 2d322b10ea401e21e6d0f40b29bf3034689121a4 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 14 Oct 2025 01:15:21 +0800 Subject: [PATCH 043/160] Fixed backing up of tradestate file during write. --- .../vendingmachine/handlers/SaveLoadHandler.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 8bb920e..a5e70e0 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -30,6 +30,7 @@ public class SaveLoadHandler { private File fileDatabase = null; private File fileNames = null; private File dirTradeState = null; + private File dirBackupTradeState = null; private SaveLoadHandler() {} @@ -42,6 +43,7 @@ public void init(MinecraftServer server) { fileDatabase = new File(Config.config_dir, "tradeDatabase.json"); dirTradeState = new File(Config.worldDir, "tradeState"); + dirBackupTradeState = new File(Config.worldDir, "backup/tradeState"); fileNames = new File(Config.worldDir, "names.json"); createFilesAndDirectories(); @@ -79,7 +81,6 @@ public Future writeDatabase() { public void loadTradeState() { if (dirTradeState.exists()) { - CopyPaste(dirTradeState, new File(Config.worldDir + "/backup", "tradeState")); File[] fileList = dirTradeState.listFiles(); if (fileList != null) { @@ -96,11 +97,15 @@ public void loadTradeState() { } public List> writeTradeState(Collection players) { + if (!dirBackupTradeState.exists()) { + CopyPaste(dirTradeState, dirBackupTradeState); + } + TradeDatabase db = TradeDatabase.INSTANCE; List> futures = new ArrayList<>(); for (UUID player : players) { File playerFile = new File(dirTradeState, player.toString() + ".json"); - CopyPaste(playerFile, new File(Config.worldDir + "/backup", player.toString() + ".json")); + CopyPaste(playerFile, new File(dirBackupTradeState, player.toString() + ".json")); NBTTagCompound state = db.writeTradeStateToNBT(new NBTTagCompound(), player); futures.add(FileIO.WriteToFile(playerFile, out -> NBTConverter.NBTtoJSON_Compound(state, out, true))); } From f560ff8a90a3c3f4f13be4120c517c138938e639 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 14 Oct 2025 19:14:43 +0800 Subject: [PATCH 044/160] Fixed bug where coins from MP session would persist into SP worlds. Cleaned up load/unload. --- .../handlers/SaveLoadHandler.java | 2 ++ .../vendingmachine/trade/TradeDatabase.java | 1 + .../vendingmachine/trade/TradeManager.java | 19 +++++++++++-------- .../vendingmachine/util/JsonHelper.java | 4 ---- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index a5e70e0..5ae0e59 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -48,6 +48,8 @@ public void init(MinecraftServer server) { createFilesAndDirectories(); + unloadAll(); + loadDatabase(); loadTradeState(); loadNames(); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 5bf941c..4a4ca50 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -41,6 +41,7 @@ public void clear() { public void clearTradeState(UUID player) { tradeGroups.forEach((k, v) -> v.clearTradeState(player)); + TradeManager.INSTANCE.clearCurrency(player); } public TradeGroup getTradeGroupFromId(UUID tgId) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 3ae8fe6..bfc5a31 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -105,14 +105,7 @@ public List getAvailableTradeGroups(UUID player) { public void populateCurrencyFromNBT(NBTTagCompound nbt, UUID player, boolean merge) { NBTTagList tagList = nbt.getTagList("playerCurrency", Constants.NBT.TAG_COMPOUND); if (!merge) { - if (player == null) { - this.playerCurrency.clear(); - this.invalidCurrency.clear(); - } else { - this.playerCurrency.remove(player); - this.invalidCurrency.remove(player); - } - + this.clearCurrency(player); } this.playerCurrency.computeIfAbsent(player, k -> new HashMap<>()); for (int i = 0; i < tagList.tagCount(); i++) { @@ -185,4 +178,14 @@ public void addCurrency(UUID playerId, CurrencyItem mapped) { } this.hasCurrencyUpdate = true; } + + public void clearCurrency(UUID player) { + if (player == null) { + this.playerCurrency.clear(); + this.invalidCurrency.clear(); + } else { + this.playerCurrency.remove(player); + this.invalidCurrency.remove(player); + } + } } diff --git a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java index de316a9..f3390d0 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java +++ b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java @@ -50,7 +50,6 @@ public static NBTTagCompound ItemStackToJson(BigItemStack stack, NBTTagCompound public static void populateTradeDatabaseFromFile(File file) { TradeDatabase db = TradeDatabase.INSTANCE; - db.clear(); Function readNbt = f -> NBTConverter .JSONtoNBT_Object(FileIO.ReadFromFile(f), new NBTTagCompound(), true); @@ -59,8 +58,6 @@ public static void populateTradeDatabaseFromFile(File file) { } public static void populateTradeStateFromFiles(List files) { - TradeDatabase db = TradeDatabase.INSTANCE; - db.clearTradeState(null); files.forEach(JsonHelper::populateTradeStateFromFile); } @@ -71,7 +68,6 @@ public static void populateTradeStateFromFile(File file) { } public static void populateNameCacheFromFile(File file) { - NameCache.INSTANCE.clear(); JsonObject json = FileIO.ReadFromFile(file); NBTTagCompound nbt = NBTConverter.JSONtoNBT_Object(json, new NBTTagCompound(), true); From 34896d7c1526869811fd0b82e771ecacd6e03c32 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Tue, 14 Oct 2025 19:09:12 +0200 Subject: [PATCH 045/160] update --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 38202ca..1c677c1 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.14-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.15-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.2-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.34:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.42:dev") } // deps may transitively add Baubles, so we replace it From 53e020acb7ddba6893e73694efeb1048fe011942 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 15 Oct 2025 02:02:49 +0800 Subject: [PATCH 046/160] Pull CurrencyType out of CurrencyItem class --- .../blocks/MTEVendingMachine.java | 9 ++-- .../vendingmachine/blocks/gui/CoinButton.java | 6 +-- .../blocks/gui/MTEVendingMachineGui.java | 19 +++---- .../network/handlers/NetCurrencySync.java | 5 +- .../vendingmachine/trade/CurrencyItem.java | 54 +------------------ .../vendingmachine/trade/CurrencyType.java | 53 ++++++++++++++++++ .../vendingmachine/trade/TradeManager.java | 9 ++-- 7 files changed, 79 insertions(+), 76 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 41cdc09..afc81be 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -42,6 +42,7 @@ import com.cubefury.vendingmachine.network.handlers.NetTradeRequestSync; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; +import com.cubefury.vendingmachine.trade.CurrencyType; import com.cubefury.vendingmachine.trade.Trade; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeManager; @@ -265,9 +266,9 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { UUID currentPlayer = NameCache.INSTANCE.getUUIDFromPlayer(this.getCurrentUser()); TradeManager.INSTANCE.playerCurrency.putIfAbsent(currentPlayer, new HashMap<>()); - Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(currentPlayer); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(currentPlayer); - Map newCoinInventory = new HashMap<>(); + Map newCoinInventory = new HashMap<>(); for (CurrencyItem ci : trade.fromCurrency) { int oldValue = coinInventory.get(ci.type); if (!coinInventory.containsKey(ci.type) || oldValue < ci.value) { @@ -308,7 +309,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } } - for (Map.Entry entry : newCoinInventory.entrySet()) { + for (Map.Entry entry : newCoinInventory.entrySet()) { if (entry.getValue() == 0) { coinInventory.remove(entry.getKey()); } else { @@ -605,7 +606,7 @@ public boolean inputCurrencySatisfied(List currencyItems, UUID pla if (currencyItems == null || currencyItems.isEmpty()) { return true; } - Map availableCurrency = TradeManager.INSTANCE.playerCurrency.get(player); + Map availableCurrency = TradeManager.INSTANCE.playerCurrency.get(player); if (availableCurrency == null) { return false; } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java index 88f4b14..b8d52f1 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java @@ -5,14 +5,14 @@ import com.cleanroommc.modularui.api.drawable.IDrawable; import com.cleanroommc.modularui.api.widget.Interactable; import com.cleanroommc.modularui.widgets.ToggleButton; -import com.cubefury.vendingmachine.trade.CurrencyItem; +import com.cubefury.vendingmachine.trade.CurrencyType; public class CoinButton extends ToggleButton { private final TradeMainPanel panel; - private final CurrencyItem.CurrencyType type; + private final CurrencyType type; - public CoinButton(TradeMainPanel panel, CurrencyItem.CurrencyType type) { + public CoinButton(TradeMainPanel panel, CurrencyType type) { super(); background(IDrawable.EMPTY); selectedBackground(IDrawable.EMPTY); 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 4421be0..175c5f1 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -49,6 +49,7 @@ import com.cubefury.vendingmachine.network.handlers.NetTradeDisplaySync; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; +import com.cubefury.vendingmachine.trade.CurrencyType; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeManager; @@ -67,7 +68,7 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { private boolean ejectItems = false; private boolean ejectCoins = false; - private final Map ejectSingleCoin = new HashMap<>(); + private final Map ejectSingleCoin = new HashMap<>(); private final Map> displayedTradesTiles = new HashMap<>(); private final Map> displayedTradesList = new HashMap<>(); private final List tradeCategories = new ArrayList<>(); @@ -122,7 +123,7 @@ public MTEVendingMachineGui(MTEVendingMachine base) { super(base); this.base = base; - for (CurrencyItem.CurrencyType type : CurrencyItem.CurrencyType.values()) { + for (CurrencyType type : CurrencyType.values()) { ejectSingleCoin.put(type, false); } @@ -285,7 +286,7 @@ private SearchBar createSearchBar() { } // Eject code is in GUI instead of MTE since the syncers are per-gui instance - private void doEjectCoin(CurrencyItem.CurrencyType type) { + private void doEjectCoin(CurrencyType type) { if (this.guiData.isClient()) { return; } @@ -320,9 +321,9 @@ private void doEjectCoins() { return; } - Map coins = TradeManager.INSTANCE.playerCurrency + Map coins = TradeManager.INSTANCE.playerCurrency .getOrDefault(currentUser, new HashMap<>()); - for (Map.Entry entry : coins.entrySet()) { + for (Map.Entry entry : coins.entrySet()) { for (ItemStack ejectable : new CurrencyItem(entry.getKey(), entry.getValue()).itemize()) { base.spawnItem(ejectable); } @@ -573,9 +574,9 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { int coinCount = 0; UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()); - Map currentAmounts = TradeManager.INSTANCE.playerCurrency + Map currentAmounts = TradeManager.INSTANCE.playerCurrency .getOrDefault(playerId, Collections.EMPTY_MAP); - for (CurrencyItem.CurrencyType type : CurrencyItem.CurrencyType.values()) { + for (CurrencyType type : CurrencyType.values()) { coinColumn.child( new Row().child( new CoinButton(panel, type).overlay( @@ -594,7 +595,7 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { builder.setAutoUpdate(true); })) .child(IKey.dynamic(() -> { - Map currencyMap = TradeManager.INSTANCE.playerCurrency + Map currencyMap = TradeManager.INSTANCE.playerCurrency .getOrDefault(playerId, Collections.EMPTY_MAP); return getReadableStringFromCoinAmount( currencyMap.get(type) == null ? 0 : currencyMap.get(type)); @@ -649,7 +650,7 @@ protected void registerSyncValues(PanelSyncManager syncManager) { syncManager.syncValue("ejectItems", ejectItemsSyncer); syncManager.syncValue("ejectCoins", ejectCoinsSyncer); - for (CurrencyItem.CurrencyType type : CurrencyItem.CurrencyType.values()) { + for (CurrencyType type : CurrencyType.values()) { BooleanSyncValue ejectCoinSyncer = new BooleanSyncValue(() -> this.ejectSingleCoin.get(type), val -> { this.ejectSingleCoin.put(type, val); if (val) { diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java index 2731569..30a7ae0 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java @@ -16,6 +16,7 @@ import com.cubefury.vendingmachine.network.PacketTypeRegistry; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; +import com.cubefury.vendingmachine.trade.CurrencyType; import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.NBTConverter; @@ -51,7 +52,7 @@ public static void sendPlayerCurrency(@Nonnull EntityPlayerMP player, CurrencyIt PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); } - public static void resetPlayerCurrency(@Nonnull EntityPlayerMP player, @Nullable CurrencyItem.CurrencyType type) { + public static void resetPlayerCurrency(@Nonnull EntityPlayerMP player, @Nullable CurrencyType type) { NBTTagCompound payload = new NBTTagCompound(); payload.setString("dataType", "currencyReset"); if (type != null) { @@ -87,7 +88,7 @@ public static void onClient(NBTTagCompound message) { } case "currencyReset" -> TradeManager.INSTANCE.resetCurrency( player, - message.hasKey("type") ? CurrencyItem.CurrencyType.getTypeFromId(message.getString("type")) : null); + message.hasKey("type") ? 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/trade/CurrencyItem.java b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java index a0535af..646c790 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java @@ -9,18 +9,11 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import com.cleanroommc.modularui.drawable.UITexture; -import com.cubefury.vendingmachine.VendingMachine; -import com.cubefury.vendingmachine.util.Translator; - -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; - public class CurrencyItem { public CurrencyType type; public int value; - private static final Map typeMap = new HashMap<>(); + public static final Map typeMap = new HashMap<>(); private static final String[] coinSuffixes = new String[] { "IV", "III", "II", "I", "" }; private static final int[] coinValues = new int[] { 10000, 1000, 100, 10, 1 }; @@ -59,51 +52,6 @@ public ItemStack getItemRepresentation() { return new ItemStack(outputItem, value); } - public enum CurrencyType { - - ADVENTURE("adventure", "dreamcraft:item.CoinAdventure", "gui/icons/itemCoinAdventure.png"), - BEES("bees", "dreamcraft:item.CoinBees", "gui/icons/itemCoinBees.png"), - BLOOD("blood", "dreamcraft:item.CoinBlood", "gui/icons/itemCoinBlood.png"), - CHEMIST("chemist", "dreamcraft:item.CoinChemist", "gui/icons/itemCoinChemist.png"), - COOK("cook", "dreamcraft:item.CoinCook", "gui/icons/itemCoinCook.png"), - DARK_WIZARD("darkWizard", "dreamcraft:item.CoinDarkWizard", "gui/icons/itemCoinDarkWizard.png"), - FARMER("farmer", "dreamcraft:item.CoinFarmer", "gui/icons/itemCoinFarmer.png"), - FLOWER("flower", "dreamcraft:item.CoinFlower", "gui/icons/itemCoinFlower.png"), - FORESTRY("forestry", "dreamcraft:item.CoinForestry", "gui/icons/itemCoinForestry.png"), - SMITH("smith", "dreamcraft:item.CoinSmith", "gui/icons/itemCoinSmith.png"), - SPACE("space", "dreamcraft:item.CoinSpace", "gui/icons/itemCoinSpace.png"), - SURVIVOR("survivor", "dreamcraft:item.CoinSurvivor", "gui/icons/itemCoinSurvivor.png"), - TECHNICIAN("technician", "dreamcraft:item.CoinTechnician", "gui/icons/itemCoinTechnician.png"), - WITCH("witch", "dreamcraft:item.CoinWitch", "gui/icons/itemCoinWitch.png"), - // comment before semicolon to reduce merge conflicts - ; - - public final String id; - public final String itemPrefix; - public final UITexture texture; - - CurrencyType(String id, String itemPrefix, String texture) { - this.id = id; - this.itemPrefix = itemPrefix; - this.texture = UITexture.builder() - .location(VendingMachine.MODID, texture) - .imageSize(32, 32) - .name("VM_UI_Coin_" + id) - .build(); - - typeMap.put(this.id, this); - } - - public static CurrencyType getTypeFromId(String type) { - return typeMap.get(type); - } - - @SideOnly(Side.CLIENT) - public String getLocalizedName() { - return Translator.translate("vendingmachine.coin." + this.id); - } - } - public CurrencyItem(CurrencyType type, int value) { this.type = type; this.value = value; diff --git a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java new file mode 100644 index 0000000..8851367 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java @@ -0,0 +1,53 @@ +package com.cubefury.vendingmachine.trade; + +import com.cleanroommc.modularui.drawable.UITexture; +import com.cubefury.vendingmachine.VendingMachine; +import com.cubefury.vendingmachine.util.Translator; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public enum CurrencyType { + + ADVENTURE("adventure", "dreamcraft:item.CoinAdventure", "gui/icons/itemCoinAdventure.png"), + BEES("bees", "dreamcraft:item.CoinBees", "gui/icons/itemCoinBees.png"), + BLOOD("blood", "dreamcraft:item.CoinBlood", "gui/icons/itemCoinBlood.png"), + CHEMIST("chemist", "dreamcraft:item.CoinChemist", "gui/icons/itemCoinChemist.png"), + COOK("cook", "dreamcraft:item.CoinCook", "gui/icons/itemCoinCook.png"), + DARK_WIZARD("darkWizard", "dreamcraft:item.CoinDarkWizard", "gui/icons/itemCoinDarkWizard.png"), + FARMER("farmer", "dreamcraft:item.CoinFarmer", "gui/icons/itemCoinFarmer.png"), + FLOWER("flower", "dreamcraft:item.CoinFlower", "gui/icons/itemCoinFlower.png"), + FORESTRY("forestry", "dreamcraft:item.CoinForestry", "gui/icons/itemCoinForestry.png"), + SMITH("smith", "dreamcraft:item.CoinSmith", "gui/icons/itemCoinSmith.png"), + SPACE("space", "dreamcraft:item.CoinSpace", "gui/icons/itemCoinSpace.png"), + SURVIVOR("survivor", "dreamcraft:item.CoinSurvivor", "gui/icons/itemCoinSurvivor.png"), + TECHNICIAN("technician", "dreamcraft:item.CoinTechnician", "gui/icons/itemCoinTechnician.png"), + WITCH("witch", "dreamcraft:item.CoinWitch", "gui/icons/itemCoinWitch.png"), + // comment before semicolon to reduce merge conflicts + ; + + public final String id; + public final String itemPrefix; + public final UITexture texture; + + CurrencyType(String id, String itemPrefix, String texture) { + this.id = id; + this.itemPrefix = itemPrefix; + this.texture = UITexture.builder() + .location(VendingMachine.MODID, texture) + .imageSize(32, 32) + .name("VM_UI_Coin_" + id) + .build(); + + CurrencyItem.typeMap.put(this.id, this); + } + + public static CurrencyType getTypeFromId(String type) { + return CurrencyItem.typeMap.get(type); + } + + @SideOnly(Side.CLIENT) + public String getLocalizedName() { + return Translator.translate("vendingmachine.coin." + this.id); + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index bfc5a31..058f734 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -26,7 +26,7 @@ public class TradeManager { private final Map> availableTrades = new HashMap<>(); private final List noConditionTrades = new ArrayList<>(); - public final Map> playerCurrency = new HashMap<>(); + public final Map> playerCurrency = new HashMap<>(); // For writeback to file in original format, to prevent data loss private final Map> invalidCurrency = new HashMap<>(); @@ -110,8 +110,7 @@ public void populateCurrencyFromNBT(NBTTagCompound nbt, UUID player, boolean mer this.playerCurrency.computeIfAbsent(player, k -> new HashMap<>()); for (int i = 0; i < tagList.tagCount(); i++) { NBTTagCompound currencyEntry = tagList.getCompoundTagAt(i); - CurrencyItem.CurrencyType type = CurrencyItem.CurrencyType - .getTypeFromId(currencyEntry.getString("currency")); + CurrencyType type = CurrencyType.getTypeFromId(currencyEntry.getString("currency")); if (type == null) { VendingMachine.LOG.warn("Unknown currency type found: {}", currencyEntry.getString("currency")); this.invalidCurrency.computeIfAbsent(player, k -> new ArrayList<>()); @@ -136,7 +135,7 @@ public NBTTagCompound writeCurrencyToNBT(NBTTagCompound nbt, @Nonnull UUID playe return nbt; } NBTTagList nbtCurrencyList = new NBTTagList(); - for (Map.Entry entry : this.playerCurrency.get(player) + for (Map.Entry entry : this.playerCurrency.get(player) .entrySet()) { NBTTagCompound currencyEntry = new NBTTagCompound(); currencyEntry.setString("currency", entry.getKey().id); @@ -153,7 +152,7 @@ public NBTTagCompound writeCurrencyToNBT(NBTTagCompound nbt, @Nonnull UUID playe return nbt; } - public void resetCurrency(UUID playerId, CurrencyItem.CurrencyType type) { + public void resetCurrency(UUID playerId, CurrencyType type) { this.playerCurrency.computeIfAbsent(playerId, k -> new HashMap<>()); if (type == null) { this.playerCurrency.get(playerId) From 00339a2f83a7d431ce90f0d9d686924211fffe7f Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 15 Oct 2025 21:40:04 +0800 Subject: [PATCH 047/160] Swapped coin amount display to synchandlers --- .../blocks/gui/MTEVendingMachineGui.java | 82 +++++++++++-------- .../handlers/SaveLoadHandler.java | 3 +- 2 files changed, 49 insertions(+), 36 deletions(-) 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 175c5f1..aba4c84 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -27,6 +27,7 @@ import com.cleanroommc.modularui.utils.Alignment; import com.cleanroommc.modularui.value.IntValue; import com.cleanroommc.modularui.value.sync.BooleanSyncValue; +import com.cleanroommc.modularui.value.sync.IntSyncValue; import com.cleanroommc.modularui.value.sync.PanelSyncManager; import com.cleanroommc.modularui.widget.ParentWidget; import com.cleanroommc.modularui.widget.SingleChildWidget; @@ -174,7 +175,7 @@ public ModularPanel build(PosGuiData guiData, PanelSyncManager syncManager, UISe .get())) .child(this.searchBar) .child(createTradeUI((TradeMainPanel) panel, this.tabController)); - mainColumn.child(createCoinInventoryRow((TradeMainPanel) panel)); + mainColumn.child(createCoinInventoryRow((TradeMainPanel) panel, syncManager)); } mainColumn.child(createInventoryRow()); panel.child(mainColumn); @@ -564,7 +565,7 @@ private static String getReadableStringFromCoinAmount(int amount) { } } - private IWidget createCoinInventoryRow(TradeMainPanel panel) { + private IWidget createCoinInventoryRow(TradeMainPanel panel, PanelSyncManager syncManager) { Flow parent = new Row() // .background(GuiTextures.TEXT_FIELD_BACKGROUND) .width(162) .height(36) @@ -573,39 +574,8 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { Flow coinColumn = new Column().width(COIN_COLUMN_WIDTH); int coinCount = 0; - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()); - Map currentAmounts = TradeManager.INSTANCE.playerCurrency - .getOrDefault(playerId, Collections.EMPTY_MAP); for (CurrencyType type : CurrencyType.values()) { - coinColumn.child( - new Row().child( - new CoinButton(panel, type).overlay( - type.texture.asIcon() - .size(12)) - .size(12) - .left(0) - .syncHandler("ejectCoin_" + type.id) - .tooltipDynamic((builder) -> { - builder.clearText(); - builder.addLine(currentAmounts.getOrDefault(type, 0) + " " + type.getLocalizedName()); - builder.emptyLine(); - builder.addLine( - IKey.str(Translator.translate("vendingmachine.gui.single_coin_type_eject_hint")) - .style(IKey.GRAY, IKey.ITALIC)); - builder.setAutoUpdate(true); - })) - .child(IKey.dynamic(() -> { - Map currencyMap = TradeManager.INSTANCE.playerCurrency - .getOrDefault(playerId, Collections.EMPTY_MAP); - return getReadableStringFromCoinAmount( - currencyMap.get(type) == null ? 0 : currencyMap.get(type)); - }) - .scale(0.8f) - .asWidget() - .top(3) - .left(14) - .width(21)) - .height(14)); + coinColumn.child(createCoinDisplay(panel, type, syncManager)); if (++coinCount % COIN_COLUMN_ROW_COUNT == 0) { parent.child(coinColumn.left(3 + COIN_COLUMN_WIDTH * (coinCount / COIN_COLUMN_ROW_COUNT - 1))); coinColumn = new Column().width(COIN_COLUMN_WIDTH); @@ -617,6 +587,34 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { return parent; } + private IWidget createCoinDisplay(TradeMainPanel panel, CurrencyType type, PanelSyncManager syncManager) { + IntSyncValue coinSyncValue = ((IntSyncValue) syncManager.getSyncHandler("coinAmount_" + type.id + ":0")); + return new Row().child( + new CoinButton(panel, type).overlay( + type.texture.asIcon() + .size(12)) + .size(12) + .left(0) + .syncHandler("ejectCoin_" + type.id) + .tooltipDynamic((builder) -> { + builder.clearText(); + builder.addLine(coinSyncValue.getValue() + " " + type.getLocalizedName()); + builder.emptyLine(); + builder.addLine( + IKey.str(Translator.translate("vendingmachine.gui.single_coin_type_eject_hint")) + .style(IKey.GRAY, IKey.ITALIC)); + builder.setAutoUpdate(true); + })) + .child( + IKey.dynamic(() -> getReadableStringFromCoinAmount(coinSyncValue.getValue())) + .scale(0.8f) + .asWidget() + .top(3) + .left(14) + .width(21)) + .height(14); + } + // why is the original method private lmao private IWidget createInventoryRow() { return new Row().widthRel(1) @@ -632,25 +630,38 @@ private IWidget createInventoryRow() { @Override protected void registerSyncValues(PanelSyncManager syncManager) { super.registerSyncValues(syncManager); + + // Item Slots syncManager.registerSlotGroup("inputSlotGroup", 2, true); syncManager.registerSlotGroup("outputSlotGroup", 2, false); + // Eject Items BooleanSyncValue ejectItemsSyncer = new BooleanSyncValue(() -> this.ejectItems, val -> { this.ejectItems = val; if (this.ejectItems) { doEjectItems(); } }); + syncManager.syncValue("ejectItems", ejectItemsSyncer); + + // Eject Coins BooleanSyncValue ejectCoinsSyncer = new BooleanSyncValue(() -> this.ejectCoins, val -> { this.ejectCoins = val; if (this.ejectCoins) { doEjectCoins(); } }); - syncManager.syncValue("ejectItems", ejectItemsSyncer); syncManager.syncValue("ejectCoins", ejectCoinsSyncer); + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()); for (CurrencyType type : CurrencyType.values()) { + // Coin Value Display + IntSyncValue coinAmountSyncer = new IntSyncValue( + () -> TradeManager.INSTANCE.playerCurrency.getOrDefault(playerId, Collections.emptyMap()) + .getOrDefault(type, 0)); + syncManager.syncValue("coinAmount_" + type.id, coinAmountSyncer); + + // Eject Individual Coins BooleanSyncValue ejectCoinSyncer = new BooleanSyncValue(() -> this.ejectSingleCoin.get(type), val -> { this.ejectSingleCoin.put(type, val); if (val) { @@ -659,6 +670,7 @@ protected void registerSyncValues(PanelSyncManager syncManager) { }); syncManager.syncValue("ejectCoin_" + type.id, ejectCoinSyncer); } + } public void attemptPurchase(TradeItemDisplay display) { diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 5ae0e59..89fda28 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.Future; @@ -93,7 +94,7 @@ public void loadTradeState() { .endsWith(".json")) .collect(Collectors.toList())); } else { - JsonHelper.populateTradeStateFromFiles(new ArrayList<>()); + JsonHelper.populateTradeStateFromFiles(Collections.emptyList()); } } } From 8df80c6eaff916a348a5a75e731811e0b43ffc2c Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 15 Oct 2025 22:24:46 +0800 Subject: [PATCH 048/160] Removed homebrewed currency sync --- .../blocks/MTEVendingMachine.java | 2 - .../blocks/gui/InterceptingSlot.java | 3 - .../blocks/gui/MTEVendingMachineGui.java | 3 - .../network/PacketTypeRegistry.java | 2 - .../network/handlers/NetCurrencySync.java | 95 ------------------- 5 files changed, 105 deletions(-) delete mode 100644 src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index afc81be..7c6e17f 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -37,7 +37,6 @@ 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.NetCurrencySync; import com.cubefury.vendingmachine.network.handlers.NetTradeDisplaySync; import com.cubefury.vendingmachine.network.handlers.NetTradeRequestSync; import com.cubefury.vendingmachine.storage.NameCache; @@ -563,7 +562,6 @@ public void sendTradeUpdate() { if (this.currentUser == null) { return; } - NetCurrencySync.syncCurrencyToClient((EntityPlayerMP) this.currentUser); NetTradeDisplaySync.syncTradesToClient((EntityPlayerMP) this.currentUser, this); } 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 582335e..2a869f0 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java @@ -1,12 +1,10 @@ package com.cubefury.vendingmachine.blocks.gui; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import com.cleanroommc.modularui.utils.item.ItemStackHandler; import com.cleanroommc.modularui.widgets.slot.ModularSlot; -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 +22,6 @@ public boolean intercept(ItemStack newItem, boolean client, EntityPlayer player) this.putStack(null); if (!client) { TradeManager.INSTANCE.addCurrency(NameCache.INSTANCE.getUUIDFromPlayer(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 aba4c84..dabe338 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -46,7 +46,6 @@ import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.gui.GuiTextures; import com.cubefury.vendingmachine.gui.WidgetThemes; -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; @@ -307,7 +306,6 @@ private void doEjectCoin(CurrencyType type) { base.spawnItem(ejectable); } TradeManager.INSTANCE.resetCurrency(currentUser, type); - NetCurrencySync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), type); this.ejectSingleCoin.put(type, false); } @@ -330,7 +328,6 @@ private void doEjectCoins() { } } TradeManager.INSTANCE.resetCurrency(currentUser, null); - NetCurrencySync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), null); ejectCoins = false; } diff --git a/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java b/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java index 6def7a2..6540eef 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java +++ b/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java @@ -13,7 +13,6 @@ import com.cubefury.vendingmachine.api.network.IPacketRegistry; import com.cubefury.vendingmachine.api.util.Tuple2; 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; @@ -30,7 +29,6 @@ public class PacketTypeRegistry implements IPacketRegistry { public void init() { NetTradeDbSync.registerHandler(); - NetCurrencySync.registerHandler(); NetTradeDisplaySync.registerHandler(); NetTradeRequestSync.registerHandler(); NetSatisfiedQuestSync.registerHandler(); diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java deleted file mode 100644 index 30a7ae0..0000000 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.cubefury.vendingmachine.network.handlers; - -import java.util.UUID; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import net.minecraft.client.Minecraft; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.ResourceLocation; - -import com.cubefury.vendingmachine.VendingMachine; -import com.cubefury.vendingmachine.api.network.UnserializedPacket; -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.CurrencyType; -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 NetCurrencySync { - - private static final ResourceLocation ID_NAME = new ResourceLocation("vendingmachine:currency_sync"); - - public static void registerHandler() { - if (VendingMachine.proxy.isClient()) { - PacketTypeRegistry.INSTANCE.registerClientHandler(ID_NAME, NetCurrencySync::onClient); - } - } - - // server side code for sending currency data when player opens gui - public static void syncCurrencyToClient(@Nonnull EntityPlayerMP player) { - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); - - NBTTagCompound payload = new NBTTagCompound(); - payload.setString("dataType", "currencySync"); - NBTConverter.UuidValueType.PLAYER.writeId(playerId, payload); - payload.setTag("data", TradeManager.INSTANCE.writeCurrencyToNBT(new NBTTagCompound(), 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", "currencyAdd"); - currencyItem.writeToNBT(payload); - - PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); - } - - public static void resetPlayerCurrency(@Nonnull EntityPlayerMP player, @Nullable CurrencyType type) { - NBTTagCompound payload = new NBTTagCompound(); - 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 onClient(NBTTagCompound message) { - // Don't wipe everyone else's data if on LAN, since - // we receive only the requested player's data - // In SP and LAN, we'll have this data already anyway - if ( - Minecraft.getMinecraft() - .isIntegratedServerRunning() - ) { - return; - } - String dataType = message.getString("dataType"); - UUID player = NBTConverter.UuidValueType.PLAYER.readId(message); - switch (dataType) { - case "currencySync" -> { - TradeManager.INSTANCE.populateCurrencyFromNBT( - message.getCompoundTag("data"), - NBTConverter.UuidValueType.PLAYER.readId(message), - false); - } - case "currencyAdd" -> { - CurrencyItem currencyItem = CurrencyItem.fromNBT(message.getCompoundTag("currencyItem")); - - TradeManager.INSTANCE.addCurrency(player, currencyItem); - } - case "currencyReset" -> TradeManager.INSTANCE.resetCurrency( - player, - message.hasKey("type") ? CurrencyType.getTypeFromId(message.getString("type")) : null); - default -> VendingMachine.LOG.warn("Unknown trade state sync data received: {}", dataType); - } - } -} From 88375c53453082b560afe2febb33bf0dd16e0e33 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 15 Oct 2025 22:25:33 +0800 Subject: [PATCH 049/160] Fixed a bug where if you had exactly 10, 100, 1k or 10k of some coin, it would split it into the lower denominator, or void if you had only 1 of that coin. --- .../java/com/cubefury/vendingmachine/trade/CurrencyItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java index 646c790..495ae3f 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java @@ -37,7 +37,7 @@ public List itemize() { return outputs; } for (int i = 0; i < coinValues.length; i++) { - while (this.value > coinValues[i]) { + while (this.value >= coinValues[i]) { Item outputItem = (Item) Item.itemRegistry.getObject(this.type.itemPrefix + coinSuffixes[i]); int stackSize = Math.min(this.value / coinValues[i], outputItem.getItemStackLimit()); outputs.add(new ItemStack(outputItem, stackSize)); From cba40a956d1a83b3795c0b2207ef16aec4d3f283 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 15 Oct 2025 22:59:45 +0800 Subject: [PATCH 050/160] Address comments + bumped mui to 2.3.3 --- dependencies.gradle | 2 +- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 1c677c1..f694c70 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,7 +38,7 @@ dependencies { implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.2-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.3-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.42:dev") } 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 dabe338..61cb084 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -628,11 +628,9 @@ private IWidget createInventoryRow() { protected void registerSyncValues(PanelSyncManager syncManager) { super.registerSyncValues(syncManager); - // Item Slots syncManager.registerSlotGroup("inputSlotGroup", 2, true); syncManager.registerSlotGroup("outputSlotGroup", 2, false); - // Eject Items BooleanSyncValue ejectItemsSyncer = new BooleanSyncValue(() -> this.ejectItems, val -> { this.ejectItems = val; if (this.ejectItems) { @@ -641,7 +639,6 @@ protected void registerSyncValues(PanelSyncManager syncManager) { }); syncManager.syncValue("ejectItems", ejectItemsSyncer); - // Eject Coins BooleanSyncValue ejectCoinsSyncer = new BooleanSyncValue(() -> this.ejectCoins, val -> { this.ejectCoins = val; if (this.ejectCoins) { @@ -652,13 +649,11 @@ protected void registerSyncValues(PanelSyncManager syncManager) { UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()); for (CurrencyType type : CurrencyType.values()) { - // Coin Value Display IntSyncValue coinAmountSyncer = new IntSyncValue( () -> TradeManager.INSTANCE.playerCurrency.getOrDefault(playerId, Collections.emptyMap()) .getOrDefault(type, 0)); syncManager.syncValue("coinAmount_" + type.id, coinAmountSyncer); - // Eject Individual Coins BooleanSyncValue ejectCoinSyncer = new BooleanSyncValue(() -> this.ejectSingleCoin.get(type), val -> { this.ejectSingleCoin.put(type, val); if (val) { From 9e4d47f43610897d0059d19e8432dd8686978b67 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 16 Oct 2025 02:47:57 +0800 Subject: [PATCH 051/160] Added support for non-consumable items in a trade. --- .../blocks/MTEVendingMachine.java | 1 + .../blocks/gui/MTEVendingMachineGui.java | 42 +++++++++++----- .../blocks/gui/TradeItemDisplay.java | 8 ++-- .../betterquesting/gui/BqTradeGroup.java | 48 ------------------- .../betterquesting/gui/PanelQBTrade.java | 11 +++++ .../integration/nei/NeiRecipeHandler.java | 11 +++++ .../network/handlers/NetTradeDisplaySync.java | 2 + .../cubefury/vendingmachine/trade/Trade.java | 14 ++++++ .../assets/vendingmachine/lang/en_US.lang | 1 + 9 files changed, 75 insertions(+), 63 deletions(-) delete mode 100644 src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 7c6e17f..4104994 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -252,6 +252,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { if ( !this.inputCurrencySatisfied(trade.fromCurrency, tradeRequest.playerID) || !this.inputItemsSatisfied(trade.fromItems) + || !this.inputItemsSatisfied(trade.nonConsumedItems) ) { return false; } 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 61cb084..8294263 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -447,21 +447,39 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { // builder.add(new ItemDrawable(toItem.getBaseStack())); } builder.emptyLine(); - builder.addLine( - IKey.str(Translator.translate("vendingmachine.gui.required_inputs")) - .style(IKey.DARK_GREEN, IKey.ITALIC)); - for (CurrencyItem currencyItem : cur.fromCurrency) { + + if (!cur.fromCurrency.isEmpty() || !cur.fromItems.isEmpty()) { builder.addLine( - IKey.str(currencyItem.value + " " + currencyItem.type.getLocalizedName()) - .style(IKey.DARK_GREEN)); + IKey.lang("vendingmachine.gui.required_inputs") + .style(IKey.DARK_GREEN, IKey.ITALIC)); + for (CurrencyItem currencyItem : cur.fromCurrency) { + builder.addLine( + IKey.str(currencyItem.value + " " + currencyItem.type.getLocalizedName()) + .style(IKey.DARK_GREEN)); + } + for (BigItemStack fromItem : cur.fromItems) { + builder.addLine( + IKey.str( + fromItem.stackSize + " " + + fromItem.getBaseStack() + .getDisplayName()) + .style(IKey.DARK_GREEN)); + } } - for (BigItemStack fromItem : cur.fromItems) { + + builder.emptyLine(); + if (!cur.ncItems.isEmpty()) { builder.addLine( - IKey.str( - fromItem.stackSize + " " - + fromItem.getBaseStack() - .getDisplayName()) - .style(IKey.DARK_GREEN)); + IKey.lang("vendingmachine.gui.nc_inputs") + .style(IKey.DARK_GREEN, IKey.ITALIC)); + for (BigItemStack fromItem : cur.ncItems) { + builder.addLine( + IKey.str( + fromItem.stackSize + " " + + fromItem.getBaseStack() + .getDisplayName()) + .style(IKey.DARK_GREEN)); + } } builder.emptyLine(); diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java index 6e5e68b..615c3ab 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java @@ -14,6 +14,7 @@ public class TradeItemDisplay { public List fromCurrency; public List fromItems; + public List ncItems; public List toItems; public ItemStack display; public UUID tgID; @@ -24,11 +25,12 @@ public class TradeItemDisplay { public boolean enabled; public boolean tradeableNow; - public TradeItemDisplay(List fromCurrency, List fromItems, List toItems, - ItemStack display, UUID tgID, int tradeGroupOrder, long cooldown, String cooldownText, boolean hasCooldown, - boolean enabled, boolean tradeableNow) { + public TradeItemDisplay(List fromCurrency, List fromItems, List ncItems, + List toItems, ItemStack display, UUID tgID, int tradeGroupOrder, long cooldown, + String cooldownText, boolean hasCooldown, boolean enabled, boolean tradeableNow) { this.fromCurrency = fromCurrency; this.fromItems = fromItems; + this.ncItems = ncItems; this.toItems = toItems; this.display = display; this.tgID = tgID; diff --git a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java deleted file mode 100644 index fcdf3cc..0000000 --- a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.cubefury.vendingmachine.integration.betterquesting.gui; - -import java.util.UUID; - -import com.cubefury.vendingmachine.trade.Trade; -import com.cubefury.vendingmachine.trade.TradeDatabase; -import com.cubefury.vendingmachine.trade.TradeGroup; - -import betterquesting.api2.client.gui.misc.GuiAlign; -import betterquesting.api2.client.gui.misc.GuiTransform; -import betterquesting.api2.client.gui.misc.IGuiRect; -import betterquesting.api2.client.gui.panels.CanvasEmpty; -import betterquesting.api2.client.gui.panels.IGuiPanel; -import betterquesting.api2.client.gui.panels.lists.CanvasScrolling; - -public class BqTradeGroup { - - public static int addTradePanel(CanvasScrolling csReward, IGuiRect rectReward, UUID tradeGroup, int yOffset) { - TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroups() - .get(tradeGroup); - if (tg == null || tg.getTrades() == null) { - return yOffset; - } - for (Trade trade : tg.getTrades()) { - IGuiPanel tradeGui = trade.getTradeGui( - new GuiTransform(GuiAlign.FULL_BOX, 0, 0, rectReward.getWidth(), rectReward.getHeight(), 111)); - if (tradeGui != null) { - tradeGui.initPanel(); - CanvasEmpty tempCanvas = new CanvasEmpty( - new GuiTransform( - GuiAlign.TOP_LEFT, - 0, - yOffset, - rectReward.getWidth(), - tradeGui.getTransform() - .getHeight() - - tradeGui.getTransform() - .getY(), - 1)); - csReward.addPanel(tempCanvas); - tempCanvas.addPanel(tradeGui); - yOffset += tempCanvas.getTransform() - .getHeight(); - } - } - return yOffset; - } -} diff --git a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java index 78dfc7a..39564bc 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java @@ -42,6 +42,17 @@ public void initPanel() { x_offset += 20; } + for (int i = 0; i < trade.nonConsumedItems.size(); i++) { + BigItemStack stack = trade.nonConsumedItems.get(i) + .toBQBigItemStack(); + GuiRectangle rectangle = new GuiRectangle(x_offset, 0, 18, 18, 0); + PanelItemSlot is = PanelItemSlotBuilder.forValue(stack, rectangle) + .showCount(true) + .build(); + this.addPanel(is); + x_offset += 20; + } + for (int i = 0; i < trade.fromCurrency.size(); i++) { CurrencyItem currencyItem = trade.fromCurrency.get(i); BigItemStack stack = new BigItemStack(currencyItem.getItemRepresentation()); diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index 75ef983..c418567 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -331,6 +331,17 @@ private void loadInputs(Trade trade) { inputs.add(new PositionedStack(extractStacks(stack), x, y)); index++; } + + // TODO: Add NC annotation on top of item + for (BigItemStack stack : trade.nonConsumedItems) { + if (index >= GRID_COUNT) { + break; + } + int x = xOffset + index * SLOT_SIZE; + inputs.add(new PositionedStack(extractStacks(stack), x, y)); + index++; + } + for (CurrencyItem ci : trade.fromCurrency) { if (index >= GRID_COUNT) { break; 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 964bf83..8babf1b 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -82,6 +82,7 @@ public TradeItemDisplay formatItemDisplay() { return new TradeItemDisplay( t.fromCurrency, t.fromItems, + t.nonConsumedItems, t.toItems, t.getDisplayItem(), this.tgID, @@ -133,6 +134,7 @@ public static void syncTradesToClient(@Nonnull EntityPlayerMP player, MTEVending Trade trade = tg.getTrades() .get(i); boolean tradableNow = base.inputItemsSatisfied(trade.fromItems) + && base.inputItemsSatisfied(trade.nonConsumedItems) && base.inputCurrencySatisfied(trade.fromCurrency, playerId); trades.appendTag( new Tradable(tg.getId(), i, cooldownRemaining, enabled, tradableNow) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java index e6d0e26..8a3c70b 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java @@ -23,6 +23,7 @@ public class Trade { public final List fromCurrency = new ArrayList<>(); public final List fromItems = new ArrayList<>(); + public final List nonConsumedItems = new ArrayList<>(); public final List toItems = new ArrayList<>(); public BigItemStack displayItem = new BigItemStack(ItemPlaceholder.placeholder); @@ -45,6 +46,14 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { nbt.setTag("fromItems", fromItemsArray); } + if (!this.nonConsumedItems.isEmpty()) { + NBTTagList ncArray = new NBTTagList(); + for (BigItemStack stack : this.nonConsumedItems) { + ncArray.appendTag(JsonHelper.ItemStackToJson(stack, new NBTTagCompound())); + } + nbt.setTag("nonConsumedItems", ncArray); + } + if (!this.toItems.isEmpty()) { NBTTagList toItemsArray = new NBTTagList(); for (BigItemStack stack : this.toItems) { @@ -73,6 +82,11 @@ public void readFromNBT(NBTTagCompound nbt) { fromItems.add(JsonHelper.JsonToItemStack(fromList.getCompoundTagAt(i))); } + NBTTagList ncList = nbt.getTagList("nonConsumedItems", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < ncList.tagCount(); i++) { + nonConsumedItems.add(JsonHelper.JsonToItemStack(ncList.getCompoundTagAt(i))); + } + NBTTagList toList = nbt.getTagList("toItems", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < toList.tagCount(); i++) { toItems.add(JsonHelper.JsonToItemStack(toList.getCompoundTagAt(i))); diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 6c91d26..661c159 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -16,6 +16,7 @@ vendingmachine.gui.coin_eject=Eject All Coins vendingmachine.gui.single_coin_type_eject_hint=Shift-Click to Extract vendingmachine.gui.search=Search vendingmachine.gui.required_inputs=Requires: +vendingmachine.gui.nc_inputs=Requires (Not Consumed): vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.display_mode=Display: vendingmachine.gui.display_mode_tile=Tiles From 66f4215abed729b72cefee63c88c527f8b0f3d7c Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Thu, 16 Oct 2025 10:47:04 +0200 Subject: [PATCH 052/160] update --- dependencies.gradle | 4 ++-- settings.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index f694c70..78b21d2 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -36,11 +36,11 @@ dependencies { implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.15-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") - compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") + compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.3-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.42:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.45:dev") } // deps may transitively add Baubles, so we replace it diff --git a/settings.gradle.kts b/settings.gradle.kts index 0966c6f..76ee14e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,5 +17,5 @@ pluginManagement { } plugins { - id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.43") + id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.44") } From b8f2f24077e71e878a1da46dd1a2c8f1284cd4e4 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 16 Oct 2025 20:55:59 +0800 Subject: [PATCH 053/160] Tidied up extra newlines in tooltips --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 8294263..f47c98e 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -465,9 +465,8 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { .getDisplayName()) .style(IKey.DARK_GREEN)); } + builder.emptyLine(); } - - builder.emptyLine(); if (!cur.ncItems.isEmpty()) { builder.addLine( IKey.lang("vendingmachine.gui.nc_inputs") @@ -480,9 +479,9 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { .getDisplayName()) .style(IKey.DARK_GREEN)); } + builder.emptyLine(); } - builder.emptyLine(); builder.addLine( IKey.str(Translator.translate("vendingmachine.gui.trade_hint")) .style(IKey.GRAY)); From 0b08db48a7238e24cc44ecbf8b81de27203fe22d Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 02:13:34 +0800 Subject: [PATCH 054/160] Fix NEI recipe handler underlines --- .../betterquesting/gui/BqTradeGroup.java | 48 +++++++++++++++++++ .../integration/nei/NeiRecipeHandler.java | 19 ++++++-- 2 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java diff --git a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java new file mode 100644 index 0000000..fcdf3cc --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java @@ -0,0 +1,48 @@ +package com.cubefury.vendingmachine.integration.betterquesting.gui; + +import java.util.UUID; + +import com.cubefury.vendingmachine.trade.Trade; +import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeGroup; + +import betterquesting.api2.client.gui.misc.GuiAlign; +import betterquesting.api2.client.gui.misc.GuiTransform; +import betterquesting.api2.client.gui.misc.IGuiRect; +import betterquesting.api2.client.gui.panels.CanvasEmpty; +import betterquesting.api2.client.gui.panels.IGuiPanel; +import betterquesting.api2.client.gui.panels.lists.CanvasScrolling; + +public class BqTradeGroup { + + public static int addTradePanel(CanvasScrolling csReward, IGuiRect rectReward, UUID tradeGroup, int yOffset) { + TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroups() + .get(tradeGroup); + if (tg == null || tg.getTrades() == null) { + return yOffset; + } + for (Trade trade : tg.getTrades()) { + IGuiPanel tradeGui = trade.getTradeGui( + new GuiTransform(GuiAlign.FULL_BOX, 0, 0, rectReward.getWidth(), rectReward.getHeight(), 111)); + if (tradeGui != null) { + tradeGui.initPanel(); + CanvasEmpty tempCanvas = new CanvasEmpty( + new GuiTransform( + GuiAlign.TOP_LEFT, + 0, + yOffset, + rectReward.getWidth(), + tradeGui.getTransform() + .getHeight() + - tradeGui.getTransform() + .getY(), + 1)); + csReward.addPanel(tempCanvas); + tempCanvas.addPanel(tradeGui); + yOffset += tempCanvas.getTransform() + .getHeight(); + } + } + return yOffset; + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index c418567..b8e44be 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -47,6 +47,7 @@ import codechicken.nei.api.API; import codechicken.nei.recipe.GuiCraftingRecipe; import codechicken.nei.recipe.GuiRecipe; +import codechicken.nei.recipe.GuiRecipeCatalyst; import codechicken.nei.recipe.TemplateRecipeHandler; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Optional; @@ -197,8 +198,12 @@ public boolean isMouseOverBqCondition(int recipeIndex, int curY, UUID questId, S Point pos = GuiDraw.getMousePosition(); - int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; - int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().w) / 2; + // very cursed I'm sorry :doom: + GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); + + int guiLeft = catalystWidget.x + catalystWidget.w - 6; + int guiTop = catalystWidget.y + 9; + Point relMousePos = new Point(pos.x - guiLeft - offset.x, pos.y - guiTop - offset.y); Rectangle textArea = new Rectangle(2, curY - GuiDraw.fontRenderer.FONT_HEIGHT, width + 2, height + 1); if (textArea.contains(relMousePos)) { @@ -214,8 +219,10 @@ public boolean isMouseOnLastHovered(GuiRecipe gui, int recipeIndex) { if (lastHoveredTextArea == null || lastHoveredQuestId == null || lastHoveredRecipeIndex != recipeIndex) { return false; } - int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; - int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().h) / 2; + GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); + + int guiLeft = catalystWidget.x + catalystWidget.w - 6; + int guiTop = catalystWidget.y + 9; Point offset = gui.getRecipePosition(recipeIndex); Point pos = GuiDraw.getMousePosition(); @@ -286,7 +293,9 @@ public void drawExtras(int recipeIndex) { } else { String translatedQuestKey = getTextWithoutFormattingCodes( QuestTranslation.translateQuestName(questId, quest)); - unformatted.append(translatedQuestKey); + unformatted.append( + translatedQuestKey.length() <= 18 ? translatedQuestKey + : translatedQuestKey.substring(0, 18) + "..."); requirementString.append( isMouseOverBqCondition(recipeIndex, y, questId, unformatted.toString()) ? UNDERLINE : ""); requirementString.append(unformatted); From 1d1ad1731ac5ac0b2a86a1e8db094554320fd932 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 13:06:41 +0800 Subject: [PATCH 055/160] Revert out of scope recipe handler change. --- .../integration/nei/NeiRecipeHandler.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index b8e44be..c418567 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -47,7 +47,6 @@ import codechicken.nei.api.API; import codechicken.nei.recipe.GuiCraftingRecipe; import codechicken.nei.recipe.GuiRecipe; -import codechicken.nei.recipe.GuiRecipeCatalyst; import codechicken.nei.recipe.TemplateRecipeHandler; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Optional; @@ -198,12 +197,8 @@ public boolean isMouseOverBqCondition(int recipeIndex, int curY, UUID questId, S Point pos = GuiDraw.getMousePosition(); - // very cursed I'm sorry :doom: - GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); - - int guiLeft = catalystWidget.x + catalystWidget.w - 6; - int guiTop = catalystWidget.y + 9; - + int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; + int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().w) / 2; Point relMousePos = new Point(pos.x - guiLeft - offset.x, pos.y - guiTop - offset.y); Rectangle textArea = new Rectangle(2, curY - GuiDraw.fontRenderer.FONT_HEIGHT, width + 2, height + 1); if (textArea.contains(relMousePos)) { @@ -219,10 +214,8 @@ public boolean isMouseOnLastHovered(GuiRecipe gui, int recipeIndex) { if (lastHoveredTextArea == null || lastHoveredQuestId == null || lastHoveredRecipeIndex != recipeIndex) { return false; } - GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); - - int guiLeft = catalystWidget.x + catalystWidget.w - 6; - int guiTop = catalystWidget.y + 9; + int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; + int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().h) / 2; Point offset = gui.getRecipePosition(recipeIndex); Point pos = GuiDraw.getMousePosition(); @@ -293,9 +286,7 @@ public void drawExtras(int recipeIndex) { } else { String translatedQuestKey = getTextWithoutFormattingCodes( QuestTranslation.translateQuestName(questId, quest)); - unformatted.append( - translatedQuestKey.length() <= 18 ? translatedQuestKey - : translatedQuestKey.substring(0, 18) + "..."); + unformatted.append(translatedQuestKey); requirementString.append( isMouseOverBqCondition(recipeIndex, y, questId, unformatted.toString()) ? UNDERLINE : ""); requirementString.append(unformatted); From ac1140641b9a0efd29c4c4a066c1ee834bf526dd Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Thu, 16 Oct 2025 10:47:04 +0200 Subject: [PATCH 056/160] update --- dependencies.gradle | 4 ++-- settings.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index f694c70..78b21d2 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -36,11 +36,11 @@ dependencies { implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.15-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") - compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.8-GTNH:dev") + compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.3-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.42:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.45:dev") } // deps may transitively add Baubles, so we replace it diff --git a/settings.gradle.kts b/settings.gradle.kts index 0966c6f..76ee14e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,5 +17,5 @@ pluginManagement { } plugins { - id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.43") + id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.44") } From 5593fbb28bb710d6f12716d200a24ad9cd968f29 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 13:13:41 +0800 Subject: [PATCH 057/160] Fixed recipe underlines in NEI --- .../integration/nei/NeiRecipeHandler.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index c418567..b8e44be 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -47,6 +47,7 @@ import codechicken.nei.api.API; import codechicken.nei.recipe.GuiCraftingRecipe; import codechicken.nei.recipe.GuiRecipe; +import codechicken.nei.recipe.GuiRecipeCatalyst; import codechicken.nei.recipe.TemplateRecipeHandler; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Optional; @@ -197,8 +198,12 @@ public boolean isMouseOverBqCondition(int recipeIndex, int curY, UUID questId, S Point pos = GuiDraw.getMousePosition(); - int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; - int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().w) / 2; + // very cursed I'm sorry :doom: + GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); + + int guiLeft = catalystWidget.x + catalystWidget.w - 6; + int guiTop = catalystWidget.y + 9; + Point relMousePos = new Point(pos.x - guiLeft - offset.x, pos.y - guiTop - offset.y); Rectangle textArea = new Rectangle(2, curY - GuiDraw.fontRenderer.FONT_HEIGHT, width + 2, height + 1); if (textArea.contains(relMousePos)) { @@ -214,8 +219,10 @@ public boolean isMouseOnLastHovered(GuiRecipe gui, int recipeIndex) { if (lastHoveredTextArea == null || lastHoveredQuestId == null || lastHoveredRecipeIndex != recipeIndex) { return false; } - int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; - int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().h) / 2; + GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); + + int guiLeft = catalystWidget.x + catalystWidget.w - 6; + int guiTop = catalystWidget.y + 9; Point offset = gui.getRecipePosition(recipeIndex); Point pos = GuiDraw.getMousePosition(); @@ -286,7 +293,9 @@ public void drawExtras(int recipeIndex) { } else { String translatedQuestKey = getTextWithoutFormattingCodes( QuestTranslation.translateQuestName(questId, quest)); - unformatted.append(translatedQuestKey); + unformatted.append( + translatedQuestKey.length() <= 18 ? translatedQuestKey + : translatedQuestKey.substring(0, 18) + "..."); requirementString.append( isMouseOverBqCondition(recipeIndex, y, questId, unformatted.toString()) ? UNDERLINE : ""); requirementString.append(unformatted); From 3eb9255a89789f6aee6e9c05e3ecb8a639860c07 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 16:04:03 +0800 Subject: [PATCH 058/160] Added NC to corner of non-consumable stacks --- .../integration/nei/NeiRecipeHandler.java | 26 ++++++++++++++++--- .../assets/vendingmachine/lang/en_US.lang | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index b8e44be..ca8acac 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -271,6 +271,19 @@ public void processBqGui() { public void drawExtras(int recipeIndex) { CachedTradeRecipe recipe = (CachedTradeRecipe) this.arecipes.get(recipeIndex); + float scale = 0.5f; + GL11.glPushMatrix(); + GL11.glScalef(scale, scale, 1); + for (PositionedStack ps : recipe.ncInputs) { + GuiDraw.fontRenderer.drawString( + "NC", + (int) (ps.relx / scale), + (int) (ps.rely / scale), + Translator.getColor("vendingmachine.gui.nc_inputs_overlay_color"), + false); + } + GL11.glPopMatrix(); + GuiDraw.drawString( Translator.translate("vendingmachine.gui.requirementHeader"), 2, @@ -319,6 +332,7 @@ public void drawExtras(int recipeIndex) { public class CachedTradeRecipe extends CachedRecipe { private final List inputs = new ArrayList<>(); + private final List ncInputs = new ArrayList<>(); private final List outputs = new ArrayList<>(); private final List requirements = new ArrayList<>(); @@ -341,13 +355,12 @@ private void loadInputs(Trade trade) { index++; } - // TODO: Add NC annotation on top of item for (BigItemStack stack : trade.nonConsumedItems) { if (index >= GRID_COUNT) { break; } int x = xOffset + index * SLOT_SIZE; - inputs.add(new PositionedStack(extractStacks(stack), x, y)); + ncInputs.add(new PositionedStack(extractStacks(stack), x, y)); index++; } @@ -381,13 +394,20 @@ public PositionedStack getResult() { @Override public List getIngredients() { - return getCycledIngredients(cycleticks / 20, inputs); + List allInputs = new ArrayList<>(); + allInputs.addAll(inputs); + allInputs.addAll(ncInputs); + return getCycledIngredients(cycleticks / 20, allInputs); } @Override public List getOtherStacks() { return outputs; } + + public List getNcInputs() { + return ncInputs; + } } @Override diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 661c159..28ae3b8 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -17,6 +17,7 @@ vendingmachine.gui.single_coin_type_eject_hint=Shift-Click to Extract vendingmachine.gui.search=Search vendingmachine.gui.required_inputs=Requires: vendingmachine.gui.nc_inputs=Requires (Not Consumed): +vendingmachine.gui.nc_inputs_overlay_color=FDD835 vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.display_mode=Display: vendingmachine.gui.display_mode_tile=Tiles From fa66518c16862ce03db818dcb17ca520b51cdec8 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 17:01:36 +0800 Subject: [PATCH 059/160] Update GT package to reference new location of MTEMultiBlockBaseGui --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 61cb084..0adab80 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -56,9 +56,9 @@ import com.cubefury.vendingmachine.util.BigItemStack; import com.cubefury.vendingmachine.util.Translator; -import gregtech.api.metatileentity.implementations.gui.MTEMultiBlockBaseGui; import gregtech.api.modularui2.GTGuiTextures; import gregtech.api.modularui2.GTWidgetThemes; +import gregtech.common.gui.modularui.multiblock.base.MTEMultiBlockBaseGui; public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { @@ -475,12 +475,11 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller tabController) { PagedWidget paged = new PagedWidget<>() .width(162) - .debugName("paged") .controller(tabController) .background(GuiTextures.TEXT_FIELD_BACKGROUND) .height(146); for (TradeCategory category : this.tradeCategories) { - ListWidget tradeList = new ListWidget<>().debugName("items") + ListWidget tradeList = new ListWidget<>() .width(161) .top(1) .height(144) @@ -585,7 +584,7 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel, PanelSyncManager sy } private IWidget createCoinDisplay(TradeMainPanel panel, CurrencyType type, PanelSyncManager syncManager) { - IntSyncValue coinSyncValue = ((IntSyncValue) syncManager.getSyncHandler("coinAmount_" + type.id + ":0")); + IntSyncValue coinSyncValue = syncManager.findSyncHandler("coinAmount_" + type.id, 0, IntSyncValue.class); return new Row().child( new CoinButton(panel, type).overlay( type.texture.asIcon() From efc9aec0badb1bd38cf537843ab2836a735f1739 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 17:05:23 +0800 Subject: [PATCH 060/160] Address comments --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 0adab80..7ed6394 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -474,12 +474,14 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { // spotless:off private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller tabController) { PagedWidget paged = new PagedWidget<>() + .name("paged") .width(162) .controller(tabController) .background(GuiTextures.TEXT_FIELD_BACKGROUND) .height(146); for (TradeCategory category : this.tradeCategories) { ListWidget tradeList = new ListWidget<>() + .name("items") .width(161) .top(1) .height(144) @@ -584,7 +586,7 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel, PanelSyncManager sy } private IWidget createCoinDisplay(TradeMainPanel panel, CurrencyType type, PanelSyncManager syncManager) { - IntSyncValue coinSyncValue = syncManager.findSyncHandler("coinAmount_" + type.id, 0, IntSyncValue.class); + IntSyncValue coinSyncValue = syncManager.findSyncHandler("coinAmount_" + type.id, 0, IntSyncValue.class); return new Row().child( new CoinButton(panel, type).overlay( type.texture.asIcon() From 7bf7d976c2906eeafead8740d81198787c9d90f6 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Fri, 17 Oct 2025 17:05:10 +0200 Subject: [PATCH 061/160] update --- dependencies.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 78b21d2..0c9dec4 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.15-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.16-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.3-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.4-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.45:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.55:dev") } // deps may transitively add Baubles, so we replace it From a0ef8b22168727949f4e943652c1047e793eb5ff Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 16 Oct 2025 02:47:57 +0800 Subject: [PATCH 062/160] Added support for non-consumable items in a trade. --- .../blocks/MTEVendingMachine.java | 1 + .../blocks/gui/MTEVendingMachineGui.java | 42 +++++++++++----- .../blocks/gui/TradeItemDisplay.java | 8 ++-- .../betterquesting/gui/BqTradeGroup.java | 48 ------------------- .../betterquesting/gui/PanelQBTrade.java | 11 +++++ .../integration/nei/NeiRecipeHandler.java | 11 +++++ .../network/handlers/NetTradeDisplaySync.java | 2 + .../cubefury/vendingmachine/trade/Trade.java | 14 ++++++ .../assets/vendingmachine/lang/en_US.lang | 1 + 9 files changed, 75 insertions(+), 63 deletions(-) delete mode 100644 src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 7c6e17f..4104994 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -252,6 +252,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { if ( !this.inputCurrencySatisfied(trade.fromCurrency, tradeRequest.playerID) || !this.inputItemsSatisfied(trade.fromItems) + || !this.inputItemsSatisfied(trade.nonConsumedItems) ) { return false; } 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 7ed6394..6fa7c44 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -447,21 +447,39 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { // builder.add(new ItemDrawable(toItem.getBaseStack())); } builder.emptyLine(); - builder.addLine( - IKey.str(Translator.translate("vendingmachine.gui.required_inputs")) - .style(IKey.DARK_GREEN, IKey.ITALIC)); - for (CurrencyItem currencyItem : cur.fromCurrency) { + + if (!cur.fromCurrency.isEmpty() || !cur.fromItems.isEmpty()) { builder.addLine( - IKey.str(currencyItem.value + " " + currencyItem.type.getLocalizedName()) - .style(IKey.DARK_GREEN)); + IKey.lang("vendingmachine.gui.required_inputs") + .style(IKey.DARK_GREEN, IKey.ITALIC)); + for (CurrencyItem currencyItem : cur.fromCurrency) { + builder.addLine( + IKey.str(currencyItem.value + " " + currencyItem.type.getLocalizedName()) + .style(IKey.DARK_GREEN)); + } + for (BigItemStack fromItem : cur.fromItems) { + builder.addLine( + IKey.str( + fromItem.stackSize + " " + + fromItem.getBaseStack() + .getDisplayName()) + .style(IKey.DARK_GREEN)); + } } - for (BigItemStack fromItem : cur.fromItems) { + + builder.emptyLine(); + if (!cur.ncItems.isEmpty()) { builder.addLine( - IKey.str( - fromItem.stackSize + " " - + fromItem.getBaseStack() - .getDisplayName()) - .style(IKey.DARK_GREEN)); + IKey.lang("vendingmachine.gui.nc_inputs") + .style(IKey.DARK_GREEN, IKey.ITALIC)); + for (BigItemStack fromItem : cur.ncItems) { + builder.addLine( + IKey.str( + fromItem.stackSize + " " + + fromItem.getBaseStack() + .getDisplayName()) + .style(IKey.DARK_GREEN)); + } } builder.emptyLine(); diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java index 6e5e68b..615c3ab 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java @@ -14,6 +14,7 @@ public class TradeItemDisplay { public List fromCurrency; public List fromItems; + public List ncItems; public List toItems; public ItemStack display; public UUID tgID; @@ -24,11 +25,12 @@ public class TradeItemDisplay { public boolean enabled; public boolean tradeableNow; - public TradeItemDisplay(List fromCurrency, List fromItems, List toItems, - ItemStack display, UUID tgID, int tradeGroupOrder, long cooldown, String cooldownText, boolean hasCooldown, - boolean enabled, boolean tradeableNow) { + public TradeItemDisplay(List fromCurrency, List fromItems, List ncItems, + List toItems, ItemStack display, UUID tgID, int tradeGroupOrder, long cooldown, + String cooldownText, boolean hasCooldown, boolean enabled, boolean tradeableNow) { this.fromCurrency = fromCurrency; this.fromItems = fromItems; + this.ncItems = ncItems; this.toItems = toItems; this.display = display; this.tgID = tgID; diff --git a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java deleted file mode 100644 index fcdf3cc..0000000 --- a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.cubefury.vendingmachine.integration.betterquesting.gui; - -import java.util.UUID; - -import com.cubefury.vendingmachine.trade.Trade; -import com.cubefury.vendingmachine.trade.TradeDatabase; -import com.cubefury.vendingmachine.trade.TradeGroup; - -import betterquesting.api2.client.gui.misc.GuiAlign; -import betterquesting.api2.client.gui.misc.GuiTransform; -import betterquesting.api2.client.gui.misc.IGuiRect; -import betterquesting.api2.client.gui.panels.CanvasEmpty; -import betterquesting.api2.client.gui.panels.IGuiPanel; -import betterquesting.api2.client.gui.panels.lists.CanvasScrolling; - -public class BqTradeGroup { - - public static int addTradePanel(CanvasScrolling csReward, IGuiRect rectReward, UUID tradeGroup, int yOffset) { - TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroups() - .get(tradeGroup); - if (tg == null || tg.getTrades() == null) { - return yOffset; - } - for (Trade trade : tg.getTrades()) { - IGuiPanel tradeGui = trade.getTradeGui( - new GuiTransform(GuiAlign.FULL_BOX, 0, 0, rectReward.getWidth(), rectReward.getHeight(), 111)); - if (tradeGui != null) { - tradeGui.initPanel(); - CanvasEmpty tempCanvas = new CanvasEmpty( - new GuiTransform( - GuiAlign.TOP_LEFT, - 0, - yOffset, - rectReward.getWidth(), - tradeGui.getTransform() - .getHeight() - - tradeGui.getTransform() - .getY(), - 1)); - csReward.addPanel(tempCanvas); - tempCanvas.addPanel(tradeGui); - yOffset += tempCanvas.getTransform() - .getHeight(); - } - } - return yOffset; - } -} diff --git a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java index 78dfc7a..39564bc 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/PanelQBTrade.java @@ -42,6 +42,17 @@ public void initPanel() { x_offset += 20; } + for (int i = 0; i < trade.nonConsumedItems.size(); i++) { + BigItemStack stack = trade.nonConsumedItems.get(i) + .toBQBigItemStack(); + GuiRectangle rectangle = new GuiRectangle(x_offset, 0, 18, 18, 0); + PanelItemSlot is = PanelItemSlotBuilder.forValue(stack, rectangle) + .showCount(true) + .build(); + this.addPanel(is); + x_offset += 20; + } + for (int i = 0; i < trade.fromCurrency.size(); i++) { CurrencyItem currencyItem = trade.fromCurrency.get(i); BigItemStack stack = new BigItemStack(currencyItem.getItemRepresentation()); diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index 75ef983..c418567 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -331,6 +331,17 @@ private void loadInputs(Trade trade) { inputs.add(new PositionedStack(extractStacks(stack), x, y)); index++; } + + // TODO: Add NC annotation on top of item + for (BigItemStack stack : trade.nonConsumedItems) { + if (index >= GRID_COUNT) { + break; + } + int x = xOffset + index * SLOT_SIZE; + inputs.add(new PositionedStack(extractStacks(stack), x, y)); + index++; + } + for (CurrencyItem ci : trade.fromCurrency) { if (index >= GRID_COUNT) { break; 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 964bf83..8babf1b 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -82,6 +82,7 @@ public TradeItemDisplay formatItemDisplay() { return new TradeItemDisplay( t.fromCurrency, t.fromItems, + t.nonConsumedItems, t.toItems, t.getDisplayItem(), this.tgID, @@ -133,6 +134,7 @@ public static void syncTradesToClient(@Nonnull EntityPlayerMP player, MTEVending Trade trade = tg.getTrades() .get(i); boolean tradableNow = base.inputItemsSatisfied(trade.fromItems) + && base.inputItemsSatisfied(trade.nonConsumedItems) && base.inputCurrencySatisfied(trade.fromCurrency, playerId); trades.appendTag( new Tradable(tg.getId(), i, cooldownRemaining, enabled, tradableNow) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java index e6d0e26..8a3c70b 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java @@ -23,6 +23,7 @@ public class Trade { public final List fromCurrency = new ArrayList<>(); public final List fromItems = new ArrayList<>(); + public final List nonConsumedItems = new ArrayList<>(); public final List toItems = new ArrayList<>(); public BigItemStack displayItem = new BigItemStack(ItemPlaceholder.placeholder); @@ -45,6 +46,14 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { nbt.setTag("fromItems", fromItemsArray); } + if (!this.nonConsumedItems.isEmpty()) { + NBTTagList ncArray = new NBTTagList(); + for (BigItemStack stack : this.nonConsumedItems) { + ncArray.appendTag(JsonHelper.ItemStackToJson(stack, new NBTTagCompound())); + } + nbt.setTag("nonConsumedItems", ncArray); + } + if (!this.toItems.isEmpty()) { NBTTagList toItemsArray = new NBTTagList(); for (BigItemStack stack : this.toItems) { @@ -73,6 +82,11 @@ public void readFromNBT(NBTTagCompound nbt) { fromItems.add(JsonHelper.JsonToItemStack(fromList.getCompoundTagAt(i))); } + NBTTagList ncList = nbt.getTagList("nonConsumedItems", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < ncList.tagCount(); i++) { + nonConsumedItems.add(JsonHelper.JsonToItemStack(ncList.getCompoundTagAt(i))); + } + NBTTagList toList = nbt.getTagList("toItems", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < toList.tagCount(); i++) { toItems.add(JsonHelper.JsonToItemStack(toList.getCompoundTagAt(i))); diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 6c91d26..661c159 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -16,6 +16,7 @@ vendingmachine.gui.coin_eject=Eject All Coins vendingmachine.gui.single_coin_type_eject_hint=Shift-Click to Extract vendingmachine.gui.search=Search vendingmachine.gui.required_inputs=Requires: +vendingmachine.gui.nc_inputs=Requires (Not Consumed): vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.display_mode=Display: vendingmachine.gui.display_mode_tile=Tiles From b8af72854aac945cf30ffeb4547a580245ce04f1 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 16 Oct 2025 20:55:59 +0800 Subject: [PATCH 063/160] Tidied up extra newlines in tooltips --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 6fa7c44..683c962 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -465,9 +465,8 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { .getDisplayName()) .style(IKey.DARK_GREEN)); } + builder.emptyLine(); } - - builder.emptyLine(); if (!cur.ncItems.isEmpty()) { builder.addLine( IKey.lang("vendingmachine.gui.nc_inputs") @@ -480,9 +479,9 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { .getDisplayName()) .style(IKey.DARK_GREEN)); } + builder.emptyLine(); } - builder.emptyLine(); builder.addLine( IKey.str(Translator.translate("vendingmachine.gui.trade_hint")) .style(IKey.GRAY)); From 760207ab71ddd5ab212b1d2c40ee3af12722d549 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 02:13:34 +0800 Subject: [PATCH 064/160] Fix NEI recipe handler underlines --- .../betterquesting/gui/BqTradeGroup.java | 48 +++++++++++++++++++ .../integration/nei/NeiRecipeHandler.java | 19 ++++++-- 2 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java diff --git a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java new file mode 100644 index 0000000..fcdf3cc --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/gui/BqTradeGroup.java @@ -0,0 +1,48 @@ +package com.cubefury.vendingmachine.integration.betterquesting.gui; + +import java.util.UUID; + +import com.cubefury.vendingmachine.trade.Trade; +import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeGroup; + +import betterquesting.api2.client.gui.misc.GuiAlign; +import betterquesting.api2.client.gui.misc.GuiTransform; +import betterquesting.api2.client.gui.misc.IGuiRect; +import betterquesting.api2.client.gui.panels.CanvasEmpty; +import betterquesting.api2.client.gui.panels.IGuiPanel; +import betterquesting.api2.client.gui.panels.lists.CanvasScrolling; + +public class BqTradeGroup { + + public static int addTradePanel(CanvasScrolling csReward, IGuiRect rectReward, UUID tradeGroup, int yOffset) { + TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroups() + .get(tradeGroup); + if (tg == null || tg.getTrades() == null) { + return yOffset; + } + for (Trade trade : tg.getTrades()) { + IGuiPanel tradeGui = trade.getTradeGui( + new GuiTransform(GuiAlign.FULL_BOX, 0, 0, rectReward.getWidth(), rectReward.getHeight(), 111)); + if (tradeGui != null) { + tradeGui.initPanel(); + CanvasEmpty tempCanvas = new CanvasEmpty( + new GuiTransform( + GuiAlign.TOP_LEFT, + 0, + yOffset, + rectReward.getWidth(), + tradeGui.getTransform() + .getHeight() + - tradeGui.getTransform() + .getY(), + 1)); + csReward.addPanel(tempCanvas); + tempCanvas.addPanel(tradeGui); + yOffset += tempCanvas.getTransform() + .getHeight(); + } + } + return yOffset; + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index c418567..b8e44be 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -47,6 +47,7 @@ import codechicken.nei.api.API; import codechicken.nei.recipe.GuiCraftingRecipe; import codechicken.nei.recipe.GuiRecipe; +import codechicken.nei.recipe.GuiRecipeCatalyst; import codechicken.nei.recipe.TemplateRecipeHandler; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Optional; @@ -197,8 +198,12 @@ public boolean isMouseOverBqCondition(int recipeIndex, int curY, UUID questId, S Point pos = GuiDraw.getMousePosition(); - int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; - int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().w) / 2; + // very cursed I'm sorry :doom: + GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); + + int guiLeft = catalystWidget.x + catalystWidget.w - 6; + int guiTop = catalystWidget.y + 9; + Point relMousePos = new Point(pos.x - guiLeft - offset.x, pos.y - guiTop - offset.y); Rectangle textArea = new Rectangle(2, curY - GuiDraw.fontRenderer.FONT_HEIGHT, width + 2, height + 1); if (textArea.contains(relMousePos)) { @@ -214,8 +219,10 @@ public boolean isMouseOnLastHovered(GuiRecipe gui, int recipeIndex) { if (lastHoveredTextArea == null || lastHoveredQuestId == null || lastHoveredRecipeIndex != recipeIndex) { return false; } - int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; - int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().h) / 2; + GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); + + int guiLeft = catalystWidget.x + catalystWidget.w - 6; + int guiTop = catalystWidget.y + 9; Point offset = gui.getRecipePosition(recipeIndex); Point pos = GuiDraw.getMousePosition(); @@ -286,7 +293,9 @@ public void drawExtras(int recipeIndex) { } else { String translatedQuestKey = getTextWithoutFormattingCodes( QuestTranslation.translateQuestName(questId, quest)); - unformatted.append(translatedQuestKey); + unformatted.append( + translatedQuestKey.length() <= 18 ? translatedQuestKey + : translatedQuestKey.substring(0, 18) + "..."); requirementString.append( isMouseOverBqCondition(recipeIndex, y, questId, unformatted.toString()) ? UNDERLINE : ""); requirementString.append(unformatted); From d9d70d6f0f86531ced29eb014fb9b224c1307779 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 13:06:41 +0800 Subject: [PATCH 065/160] Revert out of scope recipe handler change. --- .../integration/nei/NeiRecipeHandler.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index b8e44be..c418567 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -47,7 +47,6 @@ import codechicken.nei.api.API; import codechicken.nei.recipe.GuiCraftingRecipe; import codechicken.nei.recipe.GuiRecipe; -import codechicken.nei.recipe.GuiRecipeCatalyst; import codechicken.nei.recipe.TemplateRecipeHandler; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Optional; @@ -198,12 +197,8 @@ public boolean isMouseOverBqCondition(int recipeIndex, int curY, UUID questId, S Point pos = GuiDraw.getMousePosition(); - // very cursed I'm sorry :doom: - GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); - - int guiLeft = catalystWidget.x + catalystWidget.w - 6; - int guiTop = catalystWidget.y + 9; - + int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; + int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().w) / 2; Point relMousePos = new Point(pos.x - guiLeft - offset.x, pos.y - guiTop - offset.y); Rectangle textArea = new Rectangle(2, curY - GuiDraw.fontRenderer.FONT_HEIGHT, width + 2, height + 1); if (textArea.contains(relMousePos)) { @@ -219,10 +214,8 @@ public boolean isMouseOnLastHovered(GuiRecipe gui, int recipeIndex) { if (lastHoveredTextArea == null || lastHoveredQuestId == null || lastHoveredRecipeIndex != recipeIndex) { return false; } - GuiRecipeCatalyst catalystWidget = gui.getRecipeCatalystWidget(); - - int guiLeft = catalystWidget.x + catalystWidget.w - 6; - int guiTop = catalystWidget.y + 9; + int guiLeft = (gui.width - gui.getRecipeCatalystWidget().w) / 2; + int guiTop = 19 + (gui.height - gui.getRecipeCatalystWidget().h) / 2; Point offset = gui.getRecipePosition(recipeIndex); Point pos = GuiDraw.getMousePosition(); @@ -293,9 +286,7 @@ public void drawExtras(int recipeIndex) { } else { String translatedQuestKey = getTextWithoutFormattingCodes( QuestTranslation.translateQuestName(questId, quest)); - unformatted.append( - translatedQuestKey.length() <= 18 ? translatedQuestKey - : translatedQuestKey.substring(0, 18) + "..."); + unformatted.append(translatedQuestKey); requirementString.append( isMouseOverBqCondition(recipeIndex, y, questId, unformatted.toString()) ? UNDERLINE : ""); requirementString.append(unformatted); From 61ad4b7dfd38e0a31fbf9f994e4d77d66ee30220 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 17:01:36 +0800 Subject: [PATCH 066/160] Update GT package to reference new location of MTEMultiBlockBaseGui --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 f47c98e..bc4f74d 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -56,9 +56,9 @@ import com.cubefury.vendingmachine.util.BigItemStack; import com.cubefury.vendingmachine.util.Translator; -import gregtech.api.metatileentity.implementations.gui.MTEMultiBlockBaseGui; import gregtech.api.modularui2.GTGuiTextures; import gregtech.api.modularui2.GTWidgetThemes; +import gregtech.common.gui.modularui.multiblock.base.MTEMultiBlockBaseGui; public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { @@ -492,12 +492,11 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller tabController) { PagedWidget paged = new PagedWidget<>() .width(162) - .debugName("paged") .controller(tabController) .background(GuiTextures.TEXT_FIELD_BACKGROUND) .height(146); for (TradeCategory category : this.tradeCategories) { - ListWidget tradeList = new ListWidget<>().debugName("items") + ListWidget tradeList = new ListWidget<>() .width(161) .top(1) .height(144) @@ -602,7 +601,7 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel, PanelSyncManager sy } private IWidget createCoinDisplay(TradeMainPanel panel, CurrencyType type, PanelSyncManager syncManager) { - IntSyncValue coinSyncValue = ((IntSyncValue) syncManager.getSyncHandler("coinAmount_" + type.id + ":0")); + IntSyncValue coinSyncValue = syncManager.findSyncHandler("coinAmount_" + type.id, 0, IntSyncValue.class); return new Row().child( new CoinButton(panel, type).overlay( type.texture.asIcon() From 3abb3d4ef8adb0ec9cecadb243f34dc05ea55d82 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 17 Oct 2025 17:05:23 +0800 Subject: [PATCH 067/160] Address comments --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 bc4f74d..683c962 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -491,12 +491,14 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { // spotless:off private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller tabController) { PagedWidget paged = new PagedWidget<>() + .name("paged") .width(162) .controller(tabController) .background(GuiTextures.TEXT_FIELD_BACKGROUND) .height(146); for (TradeCategory category : this.tradeCategories) { ListWidget tradeList = new ListWidget<>() + .name("items") .width(161) .top(1) .height(144) @@ -601,7 +603,7 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel, PanelSyncManager sy } private IWidget createCoinDisplay(TradeMainPanel panel, CurrencyType type, PanelSyncManager syncManager) { - IntSyncValue coinSyncValue = syncManager.findSyncHandler("coinAmount_" + type.id, 0, IntSyncValue.class); + IntSyncValue coinSyncValue = syncManager.findSyncHandler("coinAmount_" + type.id, 0, IntSyncValue.class); return new Row().child( new CoinButton(panel, type).overlay( type.texture.asIcon() From 87c12bbf9aeab0c4329183140077071dd464c12b Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Fri, 17 Oct 2025 17:05:10 +0200 Subject: [PATCH 068/160] update --- dependencies.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 78b21d2..0c9dec4 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.15-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.16-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.3-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.4-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.45:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.55:dev") } // deps may transitively add Baubles, so we replace it From f44cae1a89d0553b4a875ac5eaa23d6f3e8652be Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 02:39:25 +0800 Subject: [PATCH 069/160] formatted nei display with more rows --- .../integration/nei/NeiRecipeHandler.java | 30 ++++++++++-------- .../vendingmachine/textures/gui/nei.png | Bin 4280 -> 4551 bytes 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index ca8acac..a0831c4 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -59,7 +59,7 @@ public class NeiRecipeHandler extends TemplateRecipeHandler { private static final int GUI_WIDTH = 166; private static final int GRID_COUNT = 4; private static final int LINE_SPACE = GuiDraw.fontRenderer.FONT_HEIGHT + 1; - private static final int CONDITIONS_START_Y = 27 + LINE_SPACE; + private static final int CONDITIONS_START_Y = 63 + LINE_SPACE; private UUID currentPlayerId; private int textColorConditionDefault; private int textColorConditionSatisfied; @@ -179,7 +179,7 @@ public String getGuiTexture() { public void drawBackground(int recipe) { GL11.glColor4f(1, 1, 1, 1); changeTexture(getGuiTexture()); - drawTexturedModalRect(0, 0, 0, 0, GUI_WIDTH, 105); + drawTexturedModalRect(0, 0, 0, 0, GUI_WIDTH, 140); } // Caching the last hovered valid quest here is a bit jank, but it works I guess @@ -348,30 +348,36 @@ private void loadInputs(Trade trade) { int index = 0; for (BigItemStack stack : trade.fromItems) { if (index >= GRID_COUNT) { - break; + y += SLOT_SIZE; + index = 0; } int x = xOffset + index * SLOT_SIZE; inputs.add(new PositionedStack(extractStacks(stack), x, y)); index++; } - for (BigItemStack stack : trade.nonConsumedItems) { + for (CurrencyItem ci : trade.fromCurrency) { if (index >= GRID_COUNT) { - break; + y += SLOT_SIZE; + index = 0; } int x = xOffset + index * SLOT_SIZE; - ncInputs.add(new PositionedStack(extractStacks(stack), x, y)); + inputs.add(new PositionedStack(ci.getItemRepresentation(), x, y)); index++; } - for (CurrencyItem ci : trade.fromCurrency) { + y += SLOT_SIZE; + index = 0; + for (BigItemStack stack : trade.nonConsumedItems) { if (index >= GRID_COUNT) { - break; + y += SLOT_SIZE; + index = 0; } int x = xOffset + index * SLOT_SIZE; - inputs.add(new PositionedStack(ci.getItemRepresentation(), x, y)); + ncInputs.add(new PositionedStack(extractStacks(stack), x, y)); index++; } + } private void loadOutputs(Trade trade) { @@ -404,14 +410,10 @@ public List getIngredients() { public List getOtherStacks() { return outputs; } - - public List getNcInputs() { - return ncInputs; - } } @Override public void loadTransferRects() { - transferRects.add(new RecipeTransferRect(new Rectangle(75, 0, 16, 24), getOverlayIdentifier())); + transferRects.add(new RecipeTransferRect(new Rectangle(75, 16, 16, 24), getOverlayIdentifier())); } } diff --git a/src/main/resources/assets/vendingmachine/textures/gui/nei.png b/src/main/resources/assets/vendingmachine/textures/gui/nei.png index be099bde14db6222697f5ecd7b4d17806ae14222..bf64099b320ec883d2f8e35c8bb70c402a52e54e 100644 GIT binary patch delta 1790 zcmdm?cwBkIJ+6AT%bqTdAr*7p-i^%*4wq=VSgWv8ZxIjM5fdB1CdX7h9@V9bls!K1 zAGX@NV$wFPt>(U8zcuHtW!&Qwt=|9U$UU9oj|*i3&UB0GPy7G-{)K}|3?V8El1vVs zOcN9trl2yvGgf?kb+!4p+3d4B_U-$pS01;ozUJqHxrTE-@0`24SgfIEKTE>qn>HCa zyYKcrKR>^Iy7hef`nn6pWS`emJ%2ZcRUz3@hVS(z9l0~c)=U#_3O494&bTAkaHfwT zh4a7@AX&zu;LV^`&Z4kcnIV$NV5c&}Oj*VgpTZkX0;x9~4$~NX-f=jjxif5HNhoq> zFtV;^nxM)snH0l>FwJ_$Twoz{tZaAfhX=pEzu$j)?td+Yb3aWOPZTL%c+w}`Xk?wo za_W;2F){m&eGcZ4aG z9t_8RC?hlhT{5#CXk(G?k0*Wi89{-U4GLe0@7`ry>)~%DX*>>{^OisFS)3m#J+wH2poQMV*b&n~fY!B0k zsBgdj?$YUIm;*Ey6yLh-f9qtK3d%r{$TZ>U#j5h zu-w7z=}x uFoIK$!lOT@9^FB7c0w7JFrlgw>X>tu{_L21rXi962s~Z=T-G@yGywoge`sI; delta 1517 zcmX@EyhCxrJ+6AzBc3jfAr*7p-c9tA4wqhkcBN?*Jq()w|T+aSX*qSL| zvogb0mW0RWrZMQ8{`6!%*SVix`WUVVHS}6XGaDSUkYs#bQ{~Q(#d+Y^-1nRZB>u}G z3-BJ0xZl@MTyM7*Xi5#&hQjCjSrU5c-40mJzbDub#RL@i*!Xj;`p@8hQb_uq0~OgT zKbYhHp2IWT%--$bUyufIgKRm|wKq^ryW#Tn zKg<$923WBrL{2NLt^NDv;OyD6<%^#G=V~an^JU2T>1hB8Iwl8irT}M#3{QqE4hCIL z2VTYnsyM?LNwG}5n2eQRgH&{-K`(HYbA>8y>T;wyu7e-3U!3^$e!Z68Fa+p98V<-@liae|?^9 z{`k+IKTFrM_5oe{=j*q!+TY*a{&@NI_4IvW7Qn#xyuDxkdi=e;(!1}zgQ~jo{`>1M zatvpIZnEFUV{&W;lY=r-z~Np8w1hYVlw5bM1KS1)&U%KdAI}${DMAVpGJ>3>_^BsJ zH5C*eiwQqp@1e>d;KQIWgTbNRfUzNgiQym%LlY+hi!cL+8cc>h67>UWdqYC~0Qw!| e^;9Z{d@ZYc^eUh9nHSO+fWXt$&t;ucLK6VTDd+0| From 33eafc7bfd153d73182756f6730ad382118bf570 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 02:42:41 +0800 Subject: [PATCH 070/160] Fix element positions --- .../vendingmachine/integration/nei/NeiRecipeHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index a0831c4..abb1921 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -287,7 +287,7 @@ public void drawExtras(int recipeIndex) { GuiDraw.drawString( Translator.translate("vendingmachine.gui.requirementHeader"), 2, - 27, + 63, textColorConditionDefault, false); int y = CONDITIONS_START_Y; @@ -414,6 +414,6 @@ public List getOtherStacks() { @Override public void loadTransferRects() { - transferRects.add(new RecipeTransferRect(new Rectangle(75, 16, 16, 24), getOverlayIdentifier())); + transferRects.add(new RecipeTransferRect(new Rectangle(75, 5, 16, 55), getOverlayIdentifier())); } } From 3664069c84b9bc28694469b675da7c7ea45395fe Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Fri, 17 Oct 2025 22:37:06 +0200 Subject: [PATCH 071/160] update --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 0c9dec4..a09c502 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.16-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.18-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.4-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.55:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.57:dev") } // deps may transitively add Baubles, so we replace it From f3a46e8e020018955b48747e8f713927f97ce738 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 12:03:21 +0800 Subject: [PATCH 072/160] Disable trades and trade UI refresh when machine unforms --- .../vendingmachine/blocks/MTEVendingMachine.java | 8 ++++++-- .../blocks/gui/MTEVendingMachineGui.java | 4 ++-- .../blocks/gui/TradeItemDisplayWidget.java | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 4104994..4795359 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -151,7 +151,7 @@ public boolean usingAnimations() { public void sendTradeRequest(TradeItemDisplay trade) { IGregTechTileEntity baseTile = getBaseMetaTileEntity(); - if (baseTile == null) { + if (baseTile == null || !baseTile.isActive()) { return; } NetTradeRequestSync.sendTradeRequest( @@ -167,6 +167,10 @@ public void addTradeRequest(TradeRequest trade) { } public void dispenseItems() { + IGregTechTileEntity base = this.getBaseMetaTileEntity(); + if (base == null || !base.isActive()) { + return; + } if (!this.pendingTrades.isEmpty()) { TradeRequest tradeRequest = this.pendingTrades.poll(); if (!processTradeOnServer(tradeRequest)) { @@ -548,7 +552,7 @@ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { } if (aBaseMetaTileEntity.isServerSide()) { dispenseItems(); - if (this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { + if (aBaseMetaTileEntity.isActive() && this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { this.sendTradeUpdate(); } if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { 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 683c962..931c39b 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -134,12 +134,12 @@ public MTEVendingMachineGui(MTEVendingMachine base) { displayedTradesTiles.put(c, new ArrayList<>(MTEVendingMachine.MAX_TRADES)); for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { displayedTradesTiles.get(c) - .add(new TradeItemDisplayWidget(null, TradeItemDisplayWidget.DisplayType.TILE)); + .add(new TradeItemDisplayWidget(null, this.base, TradeItemDisplayWidget.DisplayType.TILE)); } displayedTradesList.put(c, new ArrayList<>(MTEVendingMachine.MAX_TRADES)); for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { displayedTradesList.get(c) - .add(new TradeItemDisplayWidget(null, TradeItemDisplayWidget.DisplayType.LIST)); + .add(new TradeItemDisplayWidget(null, this.base, TradeItemDisplayWidget.DisplayType.LIST)); } } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index fccdf13..c4391be 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -20,10 +20,13 @@ import com.cleanroommc.modularui.value.sync.GenericSyncValue; import com.cleanroommc.modularui.value.sync.SyncHandler; import com.cleanroommc.modularui.widgets.ItemDisplayWidget; +import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.gui.GuiTextures; import com.cubefury.vendingmachine.gui.WidgetThemes; import com.cubefury.vendingmachine.util.Translator; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { public enum DisplayType { @@ -49,6 +52,7 @@ public Icon getTexture() { } } + private IGregTechTileEntity baseMTE; private TradeMainPanel rootPanel; private boolean pressed = false; private IValue value; @@ -56,7 +60,8 @@ public Icon getTexture() { private TradeItemDisplay display; - public TradeItemDisplayWidget(TradeItemDisplay display, DisplayType displayType) { + public TradeItemDisplayWidget(TradeItemDisplay display, MTEVendingMachine base, DisplayType displayType) { + this.baseMTE = base.getBaseMetaTileEntity(); this.displayType = displayType; widgetTheme(WidgetThemes.THEME_TRADE_BUTTON); if (displayType == DisplayType.TILE) { @@ -82,6 +87,10 @@ public void setDisplay(TradeItemDisplay display) { this.item(display == null ? null : display.display); } + private boolean checkVmActive() { + return this.baseMTE != null && this.baseMTE.isActive(); + } + public TradeItemDisplay getDisplay() { return this.display; } @@ -106,7 +115,7 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { if (this.display.tradeableNow) { GuiDraw.drawOutline(1, 1, 45, 23, 0x883CFF00, 2); } - if (this.display.hasCooldown || !this.display.enabled) { + if (!this.checkVmActive() || this.display.hasCooldown || !this.display.enabled) { GuiDraw.drawRoundedRect( 1, 1, @@ -139,7 +148,7 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { 3, MTEVendingMachineGui.LIST_ITEM_HEIGHT - 3, this.display.tradeableNow ? 0x883CFF00 : 0x88333333); - if (this.display.hasCooldown || !this.display.enabled) { + if (!this.checkVmActive() || this.display.hasCooldown || !this.display.enabled) { GuiDraw.drawRect( 1, 1, From 654a52cfcad810ded934dde0b9455cad2f0aafb5 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 12:12:08 +0800 Subject: [PATCH 073/160] Removed clunky baseMTE reference --- .../vendingmachine/blocks/gui/TradeItemDisplayWidget.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index c4391be..5125b14 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -25,8 +25,6 @@ import com.cubefury.vendingmachine.gui.WidgetThemes; import com.cubefury.vendingmachine.util.Translator; -import gregtech.api.interfaces.tileentity.IGregTechTileEntity; - public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { public enum DisplayType { @@ -52,7 +50,7 @@ public Icon getTexture() { } } - private IGregTechTileEntity baseMTE; + private MTEVendingMachine vm; private TradeMainPanel rootPanel; private boolean pressed = false; private IValue value; @@ -61,7 +59,7 @@ public Icon getTexture() { private TradeItemDisplay display; public TradeItemDisplayWidget(TradeItemDisplay display, MTEVendingMachine base, DisplayType displayType) { - this.baseMTE = base.getBaseMetaTileEntity(); + this.vm = base; this.displayType = displayType; widgetTheme(WidgetThemes.THEME_TRADE_BUTTON); if (displayType == DisplayType.TILE) { @@ -88,7 +86,7 @@ public void setDisplay(TradeItemDisplay display) { } private boolean checkVmActive() { - return this.baseMTE != null && this.baseMTE.isActive(); + return this.vm != null && this.vm.getActive(); } public TradeItemDisplay getDisplay() { From 803d62cfb5305c32f3d0160ed2d7464f96ff00ad Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 12:38:56 +0800 Subject: [PATCH 074/160] Disabled coin insert/eject when vm is not formed --- .../blocks/gui/InterceptingSlot.java | 9 ++++++++- .../blocks/gui/MTEVendingMachineGui.java | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) 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 2a869f0..a340e1c 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java @@ -5,18 +5,25 @@ import com.cleanroommc.modularui.utils.item.ItemStackHandler; import com.cleanroommc.modularui.widgets.slot.ModularSlot; +import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; import com.cubefury.vendingmachine.trade.TradeManager; public class InterceptingSlot extends ModularSlot { - public InterceptingSlot(ItemStackHandler inputItems, int index) { + private MTEVendingMachine vm; + + public InterceptingSlot(ItemStackHandler inputItems, int index, MTEVendingMachine vm) { super(inputItems, index); + this.vm = vm; } // intercept item on both ends, but only do the post-intercept actions on server side public boolean intercept(ItemStack newItem, boolean client, EntityPlayer player) { + if (vm == null || !vm.getActive()) { + return false; + } CurrencyItem mapped = mapToCurrency(newItem); if (mapped != null) { this.putStack(null); 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 931c39b..d6f5632 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -287,7 +287,7 @@ private SearchBar createSearchBar() { // Eject code is in GUI instead of MTE since the syncers are per-gui instance private void doEjectCoin(CurrencyType type) { - if (this.guiData.isClient()) { + if (this.guiData.isClient() || this.base == null || !this.base.getActive()) { return; } UUID currentUser = NameCache.INSTANCE.getUUIDFromPlayer(base.getCurrentUser()); @@ -314,6 +314,11 @@ private void doEjectCoins() { return; } + if (!this.base.getActive()) { + ejectCoins = false; + return; + } + UUID currentUser = NameCache.INSTANCE.getUUIDFromPlayer(base.getCurrentUser()); if (!TradeManager.INSTANCE.playerCurrency.containsKey(currentUser)) { ejectCoins = false; @@ -335,6 +340,11 @@ private void doEjectItems() { if (this.guiData.isClient()) { return; } + if (!this.base.getActive()) { + ejectItems = false; + return; + } + for (int i = 0; i < MTEVendingMachine.INPUT_SLOTS; i++) { ItemStack stack = base.inputItems.getStackInSlot(i); if (stack != null) { @@ -395,7 +405,7 @@ private SlotGroupWidget createInputSlots() { return SlotGroupWidget.builder() .matrix("II", "II", "II") .key('I', index -> { - InterceptingSlot slot = new InterceptingSlot(base.inputItems, index); + InterceptingSlot slot = new InterceptingSlot(base.inputItems, index, this.base); this.inputSlots.add(slot); return new ItemSlot().slot( slot.slotGroup("inputSlotGroup") From 01ed57a4c2c236661e1b17dfd137f0537902bd4b Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 12:45:13 +0800 Subject: [PATCH 075/160] swapped to getActive() --- .../com/cubefury/vendingmachine/blocks/MTEVendingMachine.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 4795359..002f38f 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -167,8 +167,7 @@ public void addTradeRequest(TradeRequest trade) { } public void dispenseItems() { - IGregTechTileEntity base = this.getBaseMetaTileEntity(); - if (base == null || !base.isActive()) { + if (!this.getActive()) { return; } if (!this.pendingTrades.isEmpty()) { From b345def5cb62a850f0f8ef8a368f074202c56554 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 12:48:15 +0800 Subject: [PATCH 076/160] Removed unnecessary null check --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d6f5632..02798a3 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -287,7 +287,7 @@ private SearchBar createSearchBar() { // Eject code is in GUI instead of MTE since the syncers are per-gui instance private void doEjectCoin(CurrencyType type) { - if (this.guiData.isClient() || this.base == null || !this.base.getActive()) { + if (this.guiData.isClient() || !this.base.getActive()) { return; } UUID currentUser = NameCache.INSTANCE.getUUIDFromPlayer(base.getCurrentUser()); From 528796bab0cb4672f99c0f74089e4004213e28af Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 12:51:33 +0800 Subject: [PATCH 077/160] missed one --- .../com/cubefury/vendingmachine/blocks/MTEVendingMachine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 002f38f..d38077b 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -551,7 +551,7 @@ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { } if (aBaseMetaTileEntity.isServerSide()) { dispenseItems(); - if (aBaseMetaTileEntity.isActive() && this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { + if (this.getActive() && this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { this.sendTradeUpdate(); } if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { From 94e2a3a4f0308261b18a29887f1566cf3e8df2a4 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 13:08:57 +0800 Subject: [PATCH 078/160] reduced max recipes per page --- .../com/cubefury/vendingmachine/integration/nei/NEIConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java index 730f565..de47849 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java @@ -34,7 +34,7 @@ public void registerHandlerInfo(NEIRegisterHandlerInfosEvent event) { event.registerHandlerInfo( new HandlerInfo.Builder("vendingmachine", VendingMachine.NAME, VendingMachine.MODID).setHeight(104) .setWidth(166) - .setMaxRecipesPerPage(3) + .setMaxRecipesPerPage(2) .setDisplayStack(VMItems.vendingMachine) .build()); } From e5994ad261a2ad9c12a91ec6e29173cdd1861f80 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 18 Oct 2025 13:11:51 +0800 Subject: [PATCH 079/160] Changed UI height --- .../cubefury/vendingmachine/integration/nei/NEIConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java index de47849..cfcc638 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java @@ -32,9 +32,9 @@ public String getVersion() { @SubscribeEvent public void registerHandlerInfo(NEIRegisterHandlerInfosEvent event) { event.registerHandlerInfo( - new HandlerInfo.Builder("vendingmachine", VendingMachine.NAME, VendingMachine.MODID).setHeight(104) + new HandlerInfo.Builder("vendingmachine", VendingMachine.NAME, VendingMachine.MODID).setHeight(140) .setWidth(166) - .setMaxRecipesPerPage(2) + .setMaxRecipesPerPage(3) .setDisplayStack(VMItems.vendingMachine) .build()); } From 733d8a4c821ef32bc010c91f21c7a9be89fb3e4b Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Sat, 18 Oct 2025 14:04:23 +0200 Subject: [PATCH 080/160] update --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index a09c502..6eaa03a 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -40,7 +40,7 @@ dependencies { implementation("com.github.GTNewHorizons:ModularUI2:2.3.4-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.57:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.59:dev") } // deps may transitively add Baubles, so we replace it From 18ae904dd760d669de0e6e3a3d0182eca9bd1ac5 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 19 Oct 2025 03:30:48 +0800 Subject: [PATCH 081/160] ignore nbt --- .../cubefury/vendingmachine/blocks/MTEVendingMachine.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index d38077b..c3d4ca7 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -284,6 +284,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { for (BigItemStack stack : trade.fromItems) { ItemStack requiredStack = stack.getBaseStack() .copy(); + requiredStack.setTagCompound(null); 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 @@ -293,10 +294,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } ItemStack tmp = inputSlots[i].copy(); tmp.stackSize = 1; - if ( - ItemStack.areItemStacksEqual(requiredStack, tmp) - && ItemStack.areItemStackTagsEqual(requiredStack, tmp) - ) { + if (ItemStack.areItemStacksEqual(requiredStack, tmp)) { if (requiredAmount >= inputSlots[i].stackSize) { requiredAmount -= inputSlots[i].stackSize; inputSlots[i] = null; @@ -575,6 +573,7 @@ public void refreshInputSlotCache() { ItemStack stack = this.inputItems.getStackInSlot(i); if (stack != null) { BigItemStack tmp = new BigItemStack(stack); + tmp.setTagCompound(null); tmp.stackSize = 1; items.putIfAbsent(tmp, 0); items.replace(tmp, items.get(tmp) + stack.stackSize); @@ -586,6 +585,7 @@ public void refreshInputSlotCache() { public boolean inputItemsSatisfied(List fromItems) { for (BigItemStack bis : fromItems) { BigItemStack base = bis.copy(); + bis.setTagCompound(null); base.stackSize = 1; // shouldn't need this, but just in case ItemStack aeStackSearch = base.getBaseStack(); From ae4a89ba34be3a65fd23733bbe224cd2618d320c Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 19 Oct 2025 17:15:06 +0800 Subject: [PATCH 082/160] Ignore NBT for items in ME system --- .../blocks/MTEVendingMachine.java | 6 ++ .../blocks/MTEVendingUplinkHatch.java | 99 ++++++++++++++++++- .../network/handlers/NetTradeDisplaySync.java | 1 + 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index c3d4ca7..7e767fd 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -753,4 +753,10 @@ private boolean addUplinkHatch(IGregTechTileEntity aBaseMetaTileEntity, int aBas this.uplinkHatches.add(uplinkHatch); return true; } + + public void refreshMeItemCache() { + for (MTEVendingUplinkHatch hatch : this.uplinkHatches) { + hatch.refreshStorageContents(); + } + } } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index d190276..77f9867 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -3,7 +3,9 @@ import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_0; import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_1; +import java.util.ArrayList; import java.util.EnumSet; +import java.util.List; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -14,6 +16,7 @@ import com.cubefury.vendingmachine.items.VMItems; import appeng.api.config.Actionable; +import appeng.api.config.FuzzyMode; import appeng.api.implementations.IPowerChannelState; import appeng.api.networking.GridFlags; import appeng.api.networking.IGridNode; @@ -21,11 +24,13 @@ import appeng.api.networking.security.MachineSource; import appeng.api.networking.storage.IStorageGrid; import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; 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.IterationCounter; import appeng.util.item.AEItemStack; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; @@ -37,6 +42,7 @@ public class MTEVendingUplinkHatch extends MTEHatch implements IGridProxyable, I protected AENetworkProxy gridProxy = null; protected boolean additionalConnection = false; + private IItemList cachedItems; public static final int mTier = 3; @@ -172,15 +178,98 @@ private IStorageGrid accessStorage() { return null; } + public void refreshStorageContents() { + IStorageGrid storage = accessStorage(); + if (storage == null) return; + + cachedItems = storage.getItemInventory() + .getStorageList(); + } + public boolean removeItem(ItemStack remove, boolean simulate) { if (remove == null || remove.stackSize <= 0) return true; IStorageGrid storage = accessStorage(); if (storage == null) return false; - IAEItemStack stack = storage.getItemInventory() - .extractItems( + + MachineSource source = new MachineSource(this); + if (!remove.isItemStackDamageable()) { + IAEItemStack stack = storage.getItemInventory() + .extractItems(AEItemStack.create(remove), simulate ? Actionable.SIMULATE : Actionable.MODULATE, source); + return stack != null && stack.getStackSize() >= remove.stackSize; + } + VendingMachine.LOG.info("target remove: {}", remove); + + List outputList = new ArrayList<>(); + for (IAEItemStack stack : cachedItems) { + if (stack.getItem() == remove.getItem() && stack.getItemDamage() == remove.getItemDamage()) { + outputList.add(stack); + } + } + + // test + List result = new ArrayList<>(); + storage.getItemInventory() + .getSortedFuzzyItems( + result, + AEItemStack.create(remove), + FuzzyMode.IGNORE_ALL, + IterationCounter.fetchNewId()); + VendingMachine.LOG.info( + "found {} matched items with fuzzy search IGNOREALL", + result.stream() + .mapToLong(s -> s.getStackSize()) + .sum()); + + result = new ArrayList<>(); + storage.getItemInventory() + .getSortedFuzzyItems( + result, AEItemStack.create(remove), - simulate ? Actionable.SIMULATE : Actionable.MODULATE, - new MachineSource(this)); - return stack != null && stack.getStackSize() >= remove.stackSize; + FuzzyMode.PERCENT_99, + IterationCounter.fetchNewId()); + VendingMachine.LOG.info( + "found {} matched items with fuzzy search 99", + result.stream() + .mapToLong(s -> s.getStackSize()) + .sum()); + + // endtest + + long numMatch = outputList.stream() + .mapToLong(stack -> stack.getStackSize()) + .sum(); + VendingMachine.LOG.info("found {} matched items", numMatch); + if (simulate || numMatch < remove.stackSize) { + return numMatch >= remove.stackSize; + } + + // Simulate removing the needed count first, and add successful to modulateList for actual removal, + // due to possible view-only items that can't be actually extracted + long remain = remove.stackSize; + List modulateList = new ArrayList<>(); + for (IAEItemStack removable : outputList) { + long toRemove = Math.min(removable.getStackSize(), remain); + removable.setStackSize(toRemove); + IAEItemStack stack = storage.getItemInventory() + .extractItems(removable, Actionable.SIMULATE, source); + if (stack != null && stack.getItemDamage() == remove.getItemDamage()) { + modulateList.add(stack); + } else { + continue; + } + remain -= toRemove; + if (remain <= 0) { + break; + } + } + if (remain > 0) { + return false; + } + + for (IAEItemStack modulate : modulateList) { + storage.getItemInventory() + .extractItems(modulate, Actionable.MODULATE, source); + } + return true; } } 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 8babf1b..4ac7275 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -112,6 +112,7 @@ public static void syncTradesToClient(@Nonnull EntityPlayerMP player, MTEVending UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); List availableGroups = TradeManager.INSTANCE.getAvailableTradeGroups(playerId); base.refreshInputSlotCache(); + base.refreshMeItemCache(); long currentTimestamp = System.currentTimeMillis(); From adf454b67b332dcb1282f9dede857136497b5715 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 19 Oct 2025 17:27:12 +0800 Subject: [PATCH 083/160] Removed experimental code and added null check for cached items --- .../blocks/MTEVendingUplinkHatch.java | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index 77f9867..2082323 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -197,7 +197,10 @@ public boolean removeItem(ItemStack remove, boolean simulate) { .extractItems(AEItemStack.create(remove), simulate ? Actionable.SIMULATE : Actionable.MODULATE, source); return stack != null && stack.getStackSize() >= remove.stackSize; } - VendingMachine.LOG.info("target remove: {}", remove); + + if (cachedItems == null) { + return false; + } List outputList = new ArrayList<>(); for (IAEItemStack stack : cachedItems) { @@ -206,39 +209,9 @@ public boolean removeItem(ItemStack remove, boolean simulate) { } } - // test - List result = new ArrayList<>(); - storage.getItemInventory() - .getSortedFuzzyItems( - result, - AEItemStack.create(remove), - FuzzyMode.IGNORE_ALL, - IterationCounter.fetchNewId()); - VendingMachine.LOG.info( - "found {} matched items with fuzzy search IGNOREALL", - result.stream() - .mapToLong(s -> s.getStackSize()) - .sum()); - - result = new ArrayList<>(); - storage.getItemInventory() - .getSortedFuzzyItems( - result, - AEItemStack.create(remove), - FuzzyMode.PERCENT_99, - IterationCounter.fetchNewId()); - VendingMachine.LOG.info( - "found {} matched items with fuzzy search 99", - result.stream() - .mapToLong(s -> s.getStackSize()) - .sum()); - - // endtest - long numMatch = outputList.stream() .mapToLong(stack -> stack.getStackSize()) .sum(); - VendingMachine.LOG.info("found {} matched items", numMatch); if (simulate || numMatch < remove.stackSize) { return numMatch >= remove.stackSize; } From bf4933127fd2a512414d1d8cf42461e1702e24b3 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 19 Oct 2025 17:27:27 +0800 Subject: [PATCH 084/160] spotless --- .../cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index 2082323..cb3b273 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -16,7 +16,6 @@ import com.cubefury.vendingmachine.items.VMItems; import appeng.api.config.Actionable; -import appeng.api.config.FuzzyMode; import appeng.api.implementations.IPowerChannelState; import appeng.api.networking.GridFlags; import appeng.api.networking.IGridNode; @@ -30,7 +29,6 @@ import appeng.me.GridAccessException; import appeng.me.helpers.AENetworkProxy; import appeng.me.helpers.IGridProxyable; -import appeng.util.IterationCounter; import appeng.util.item.AEItemStack; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; From 466acf89d916f013f9864751f6a57e373cd2db7d Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 20 Oct 2025 10:56:49 +0800 Subject: [PATCH 085/160] Made uplink texture update correctly when powered by ME system --- .../vendingmachine/api/enums/Textures.java | 4 ++-- .../blocks/MTEVendingUplinkHatch.java | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java b/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java index 59354b4..277dfd2 100644 --- a/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java +++ b/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java @@ -20,8 +20,8 @@ public class Textures { VM_OVERLAY_ACTIVE_2 = new CustomIcon("vendingmachine:vending_machine_overlay_active_2"), VM_OVERLAY_ACTIVE_3 = new CustomIcon("vendingmachine:vending_machine_overlay_active_3"), - VUPLINK_OVERLAY_0 = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_inactive"), - VUPLINK_OVERLAY_1 = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_active"); + VUPLINK_OVERLAY_INACTIVE = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_inactive"), + VUPLINK_OVERLAY_ACTIVE = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_active"); public static final IIconContainer[] VM_OVERLAY_ACTIVE = { VM_OVERLAY_ACTIVE_0, VM_OVERLAY_ACTIVE_1, VM_OVERLAY_ACTIVE_2, VM_OVERLAY_ACTIVE_3, VM_OVERLAY_4 // bottom right not animated diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index d190276..c7c7021 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -1,7 +1,7 @@ package com.cubefury.vendingmachine.blocks; -import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_0; -import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_1; +import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_ACTIVE; +import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_INACTIVE; import java.util.EnumSet; @@ -120,12 +120,12 @@ public void securityBreak() {} @Override public ITexture[] getTexturesActive(ITexture aBaseTexture) { - return new ITexture[] { aBaseTexture, TextureFactory.of(VUPLINK_OVERLAY_1) }; + return new ITexture[] { aBaseTexture, TextureFactory.of(VUPLINK_OVERLAY_ACTIVE) }; } @Override public ITexture[] getTexturesInactive(ITexture aBaseTexture) { - return new ITexture[] { aBaseTexture, TextureFactory.of(VUPLINK_OVERLAY_0) }; + return new ITexture[] { aBaseTexture, TextureFactory.of(VUPLINK_OVERLAY_INACTIVE) }; } @Override @@ -144,6 +144,14 @@ public void onFirstTick(IGregTechTileEntity baseMetaTileEntity) { getProxy().onReady(); } + @Override + public void onPostTick(IGregTechTileEntity baseMetaTileEntity, long tick) { + if (baseMetaTileEntity.isServerSide()) { + baseMetaTileEntity.setActive(isActive()); + } + super.onPostTick(baseMetaTileEntity, tick); + } + private void updateValidGridProxySides() { if (additionalConnection) { getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); From f253d283c0d012f59773a26b800f790059e50ae1 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 20 Oct 2025 11:01:08 +0800 Subject: [PATCH 086/160] reduced frequency of active check --- .../cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index c7c7021..eba8b4f 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -146,7 +146,7 @@ public void onFirstTick(IGregTechTileEntity baseMetaTileEntity) { @Override public void onPostTick(IGregTechTileEntity baseMetaTileEntity, long tick) { - if (baseMetaTileEntity.isServerSide()) { + if (baseMetaTileEntity.isServerSide() && tick % 20 == 0) { baseMetaTileEntity.setActive(isActive()); } super.onPostTick(baseMetaTileEntity, tick); From b9d34b674924e2d43d3a707bd986b602c4d8d920 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Wed, 22 Oct 2025 21:34:42 +0200 Subject: [PATCH 087/160] update --- dependencies.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 6eaa03a..00b2fd6 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.18-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.20-GTNH:dev") implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.4-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.5-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.59:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.65:dev") } // deps may transitively add Baubles, so we replace it @@ -49,7 +49,7 @@ project.getConfigurations() final DependencySubstitutions ds = c.getResolutionStrategy() .getDependencySubstitution() ds.substitute(ds.module("com.github.GTNewHorizons:Baubles")) - .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.2.0-GTNH")) + .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.2.2-GTNH")) .withClassifier("dev") .because("Baubles-Expanded replaces Baubles") }) From c8812083ef16b0a38d33d02b14a95e2bf8b0b617 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 28 Oct 2025 20:59:36 +0800 Subject: [PATCH 088/160] Added coin add, set and reset commands. --- .../cubefury/vendingmachine/CommonProxy.java | 3 + .../command/CommandVending.java | 163 ++++++++++++++++++ .../assets/vendingmachine/lang/en_US.lang | 5 + 3 files changed, 171 insertions(+) create mode 100644 src/main/java/com/cubefury/vendingmachine/command/CommandVending.java diff --git a/src/main/java/com/cubefury/vendingmachine/CommonProxy.java b/src/main/java/com/cubefury/vendingmachine/CommonProxy.java index fe27b2d..51c4af4 100644 --- a/src/main/java/com/cubefury/vendingmachine/CommonProxy.java +++ b/src/main/java/com/cubefury/vendingmachine/CommonProxy.java @@ -5,6 +5,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraftforge.common.MinecraftForge; +import com.cubefury.vendingmachine.command.CommandVending; import com.cubefury.vendingmachine.handlers.EventHandler; import com.cubefury.vendingmachine.handlers.SaveLoadHandler; @@ -35,6 +36,8 @@ public void serverStarting(FMLServerStartingEvent event) { ICommandManager command = server.getCommandManager(); ServerCommandManager manager = (ServerCommandManager) command; + manager.registerCommand(new CommandVending()); + SaveLoadHandler.INSTANCE.init(server); } diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java new file mode 100644 index 0000000..5bea141 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -0,0 +1,163 @@ +package com.cubefury.vendingmachine.command; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ChatComponentText; + +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.CurrencyType; +import com.cubefury.vendingmachine.trade.TradeManager; +import com.cubefury.vendingmachine.util.Translator; + +public class CommandVending extends CommandBase { + + @Override + public String getCommandName() { + return "vending"; + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return "/vending [player] [coin_type|all] [amount]"; + } + + @Override + public int getRequiredPermissionLevel() { + return 2; + } + + @Override + public boolean canCommandSenderUseCommand(ICommandSender sender) { + return sender.canCommandSenderUseCommand(getRequiredPermissionLevel(), getCommandName()); + } + + @Override + public List addTabCompletionOptions(ICommandSender sender, String[] args) { + switch (args.length) { + case 1: { + return getListOfStringsMatchingLastWord(args, "set", "add", "reset"); + } + case 2: { + List suggestions = getListOfStringsMatchingLastWord( + args, + MinecraftServer.getServer() + .getAllUsernames()); + suggestions.addAll( + Arrays.stream(CurrencyType.values()) + .map(c -> c.id) + .collect(Collectors.toList())); + suggestions.add("all"); + return suggestions; + } + case 3: { + List suggestions = Arrays.stream(CurrencyType.values()) + .map(c -> c.id) + .collect(Collectors.toList()); + suggestions.add("all"); + if ( + suggestions.stream() + .anyMatch(s -> s.equals(args[2])) + ) { + return null; + } + return suggestions; + } + default: + return null; + } + } + + @Override + public void processCommand(ICommandSender sender, String[] args) { + if (args.length < 1) { + sender.addChatMessage( + new ChatComponentText( + Translator.translate("vendingmachine.command.usage") + " " + getCommandUsage(sender))); + return; + } + + String action = args[0]; + EntityPlayerMP target = null; + + if (args.length >= 2) { + target = getPlayer(sender, args[1]); + } else if (sender instanceof EntityPlayer) { + target = getCommandSenderAsPlayer(sender); + } + + if (target == null) { + sender.addChatMessage(new ChatComponentText(Translator.translate("vendingmachine.command.invalid_player"))); + return; + } + + if (action.equals("set") || action.equals("add")) { + int typeOffset = args.length >= 3 ? 2 : 1; + CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); + if (type == null && !args[typeOffset].equals("all")) { + sender.addChatMessage( + new ChatComponentText( + Translator.translate("vendingmachine.command.unknown_currency") + " " + args[typeOffset])); + return; + } + try { + int amount = Integer.parseInt(args[typeOffset + 1]); + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); + TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); + if (args[typeOffset].equals("all")) { + for (CurrencyType cur : CurrencyType.values()) { + coinInventory.putIfAbsent(cur, 0); + + coinInventory.put(cur, action.equals("add") ? coinInventory.get(cur) + amount : amount); + } + } else { + coinInventory.putIfAbsent(type, 0); + coinInventory.put(type, action.equals("add") ? coinInventory.get(type) + amount : amount); + } + } catch (NumberFormatException e) { + sender.addChatMessage( + new ChatComponentText( + Translator.translate("vendingmachine.command.usage") + " " + + getAddOrSetUsage(sender, args[0]))); + } + } else if (action.equals("reset")) { + int typeOffset = args.length >= 2 ? 2 : 1; + CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); + if (type == null && !args[typeOffset].equals("all")) { + sender.addChatMessage( + new ChatComponentText( + Translator.translate("vendingmachine.command.unknown_currency") + " " + args[typeOffset])); + return; + } + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); + TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); + if (args[typeOffset].equals("all")) { + coinInventory.clear(); + } else { + coinInventory.remove(type); + } + } else { + sender.addChatMessage( + new ChatComponentText(Translator.translate("vendingmachine.command.unknown_action") + " " + action)); + } + + } + + private String getAddOrSetUsage(ICommandSender sender, String arg) { + if (!arg.equals("add") && !arg.equals("set")) { + return getCommandUsage(sender); + } + return "/vending " + arg + " [player] [coin_type|all] [amount]"; + } +} diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 28ae3b8..e0c74d0 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -4,6 +4,11 @@ tooltip.vendingmachine=Who's even restocking this... structure.vendingmachine.hint.1=Hint 1 Dot: Tin Item Pipe Casing, ME Vending Uplink Hatch +vendingmachine.command.usage=Usage: +vendingmachine.command.invalid_player=Could not identify player +vendingmachine.command.unknown_action=Unknown action: +vendingmachine.command.unknown_currency=Unknown currency type: + vendingmachine.gui.requirementHeader=Requirements: vendingmachine.gui.requirement.unknown=Unknown Requirement vendingmachine.gui.requirement.betterquesting=Quest From dcfd79bcf176f75b981f769783155233b392012a Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 28 Oct 2025 21:16:26 +0800 Subject: [PATCH 089/160] Fixed hints for commands --- .../com/cubefury/vendingmachine/command/CommandVending.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 5bea141..9dc5041 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -28,7 +28,7 @@ public String getCommandName() { @Override public String getCommandUsage(ICommandSender sender) { - return "/vending [player] [coin_type|all] [amount]"; + return "/vending [player] "; } @Override @@ -158,6 +158,6 @@ private String getAddOrSetUsage(ICommandSender sender, String arg) { if (!arg.equals("add") && !arg.equals("set")) { return getCommandUsage(sender); } - return "/vending " + arg + " [player] [coin_type|all] [amount]"; + return "/vending " + arg + " [player] "; } } From 90b4e3a7955717dd363f59645c92d8f121be8812 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 30 Oct 2025 00:26:28 +0800 Subject: [PATCH 090/160] Fixed command arugment position checks. --- .../vendingmachine/command/CommandVending.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 9dc5041..446ec79 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -14,6 +14,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.util.ChatComponentText; +import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyType; import com.cubefury.vendingmachine.trade.TradeManager; @@ -79,7 +80,7 @@ public List addTabCompletionOptions(ICommandSender sender, String[] args @Override public void processCommand(ICommandSender sender, String[] args) { - if (args.length < 1) { + if (args.length < 2) { sender.addChatMessage( new ChatComponentText( Translator.translate("vendingmachine.command.usage") + " " + getCommandUsage(sender))); @@ -89,7 +90,8 @@ public void processCommand(ICommandSender sender, String[] args) { String action = args[0]; EntityPlayerMP target = null; - if (args.length >= 2) { + VendingMachine.LOG.info(args.length); + if (args.length > 2 && action.equals("reset") || args.length > 3) { target = getPlayer(sender, args[1]); } else if (sender instanceof EntityPlayer) { target = getCommandSenderAsPlayer(sender); @@ -101,7 +103,7 @@ public void processCommand(ICommandSender sender, String[] args) { } if (action.equals("set") || action.equals("add")) { - int typeOffset = args.length >= 3 ? 2 : 1; + int typeOffset = args.length > 3 ? 2 : 1; CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); if (type == null && !args[typeOffset].equals("all")) { sender.addChatMessage( @@ -131,7 +133,7 @@ public void processCommand(ICommandSender sender, String[] args) { + getAddOrSetUsage(sender, args[0]))); } } else if (action.equals("reset")) { - int typeOffset = args.length >= 2 ? 2 : 1; + int typeOffset = args.length > 2 ? 2 : 1; CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); if (type == null && !args[typeOffset].equals("all")) { sender.addChatMessage( From fac3f6d1e0d26c190751e8f482a3e9662a554df9 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 4 Nov 2025 12:30:20 +0800 Subject: [PATCH 091/160] Fixed coin names --- .../assets/vendingmachine/lang/en_US.lang | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 28ae3b8..d78d3bc 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -47,17 +47,17 @@ vendingmachine.category.magic=Magic vendingmachine.category.bees=Bees vendingmachine.category.misc=Miscellaneous -vendingmachine.coin.adventure=Adventure Coin -vendingmachine.coin.bees=Bees Coin -vendingmachine.coin.blood=Blood Magic Coin -vendingmachine.coin.chemist=Chemistry Coin +vendingmachine.coin.adventure=Explorer Coin +vendingmachine.coin.bees=Beekeeper Coin +vendingmachine.coin.blood=Vampire Coin +vendingmachine.coin.chemist=Chemist Coin vendingmachine.coin.cook=Cook Coin vendingmachine.coin.darkWizard=Dark Wizard Coin -vendingmachine.coin.farmer=Farming Coin -vendingmachine.coin.flower=Flower Coin -vendingmachine.coin.forestry=Forestry Coin -vendingmachine.coin.smith=Smith Coin -vendingmachine.coin.space=Space Coin +vendingmachine.coin.farmer=Farmer Coin +vendingmachine.coin.flower=Gardener Coin +vendingmachine.coin.forestry=Forest Ranger Coin +vendingmachine.coin.smith=Blacksmith Coin +vendingmachine.coin.space=Space Invaders Coin vendingmachine.coin.survivor=Survivor Coin vendingmachine.coin.technician=Technician Coin -vendingmachine.coin.witch=Witchery Coin +vendingmachine.coin.witch=Spirit Coin From 535976db38f8f2aad5078b6361978e3e61d647c0 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Tue, 4 Nov 2025 22:48:53 +0100 Subject: [PATCH 092/160] update --- dependencies.gradle | 8 ++++---- gradle.properties | 10 +++++++++- gradle/wrapper/gradle-wrapper.jar | Bin 43705 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 ++-- gradlew.bat | 4 ++-- settings.gradle.kts | 2 +- 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 00b2fd6..56d5159 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.20-GTNH:dev") - implementation("com.github.GTNewHorizons:GTNHLib:0.7.0:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.26-GTNH:dev") + implementation("com.github.GTNewHorizons:GTNHLib:0.7.7:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.5-1.7.10:dev") - implementation("com.github.GTNewHorizons:StructureLib:1.4.23:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.65:dev") + implementation("com.github.GTNewHorizons:StructureLib:1.4.24:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.95:dev") } // deps may transitively add Baubles, so we replace it diff --git a/gradle.properties b/gradle.properties index 7d6b721..1ad7da2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -87,7 +87,9 @@ usesMixinDebug = false # Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. mixinPlugin = -# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! +# Specify the package that contains all of your Mixins. The package must exist or +# the build will fail. If you have a package property defined in your mixins..json, +# it must match with this or the build will fail. mixinsPackage = # Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! @@ -163,6 +165,12 @@ curseForgeRelations = # projects. New projects should not use this parameter. # customArchiveBaseName = +# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory. +# runClientWorkingDirectory = run/client + +# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory. +# runServerWorkingDirectory = run/server + # Optional parameter to have the build automatically fail if an illegal version is used. # This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'. # The check is ONLY performed if the version is a git tag. diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9bbc975c742b298b441bfb90dbc124400a3751b9..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 642 zcmdmamFde>rVZJA^}0Q$xegf!xPEW^+5YDM%iT2bEgct9o+jH~+sJas#HZ=szO|** z=Pj=X_vx?W&DSwKck|WWn~hffsvnQ+42*W$b7b0$SCcOoZ`{W{^$^pk;4>8-A*-)$ z?n(Po`1$6Jn_u?t-L+tsPyZ2#X}8T6OS8pAU;kdgd+_Hw4z4TW0p9E!T+=f7-c&O% zFic^X{7^$?^Ho04eona9n#mGMxKhA=~8B%JN`M zMhm5wc-2v)$``sY$!Q`9xiU@DhI73ZxiGEKg>yIPs)NmWwMdF-ngLXpZSqV5ez36n zVkxF2rjrjWR+_xr6e6@_u@s~2uv{9vi*1pj2)BjFD+-%@&pRVP1f{O1glxTOp2-62Ph;v z`N1+vCd)9ea)af*Ol1*JCfnp$%Uu}%OuoN7g2}3C@`L5FlP#(sA=|h@iixuZC?qp^ z=L$=v$ZoI}|87Wh=&h7udff{aieKr*l+zDp?pf)_bbRvUf>kn;HCDMXNlgbbo!QRK I1x7am0No)LiU0rr delta 584 zcmexzm1*ZyrVZJAexH5Moc8h7)w{^+t*dqJ%=yhh23L$9JpFV=_k`zJ-?Q4DI*eSe z+ES)HSrVnWLtJ&)lO%hRkV9zl5qqWRt0e;bb zPPo`)y?HTAyZI&u&X<|2$FDHCf4;!v8}p=?Tm`^F0`u(|1ttf~&t$qP3KUSD>@TJQ zRwJ}Pim6NzEc8KA6)e;S6gs8=7IIL8sQL*MYEuRYO;Uj<%3UbMbV&^&!Zvx+LKmjT z8Zch6rYP7Tw?$Hn(UTJwWiS=$f{lB(C=e*%usDV})0AQIK~sat=ND@+Gg*Pyij!rR z*fa02W|%BsV++>4W{DKDGSIUEHd2$P+8ct!RF+CHDowUuTEZOZ%rJSQv*qOXOSPDN zT|sP-$p*_3ncsWB*qoD7JQcyZ9xan%cJP6Tb4-?AZpr*F6v98hoNaPJm@HV`yya5N z))6pqFXn@}P(3T0nEzM8*c_9KtE9o|_pFd&K35GBXP^9Kg(b6GH-z8S4GDzIl~T+b zdLd#meKKHu$5u))8cu$=GKINkGDPOUD)!0$C(BH(U!}!-e;Q0ok8Sc?V1zRO04>ts AA^-pY diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b..d4081da 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index faf9300..23d15a9 100755 --- a/gradlew +++ b/gradlew @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a21..db3a6ac 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle.kts b/settings.gradle.kts index 76ee14e..1cd4b02 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,5 +17,5 @@ pluginManagement { } plugins { - id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.44") + id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.48") } From 3cbc071ded00a1c693bd48c979a59daee4cb2523 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 6 Nov 2025 17:33:56 +0800 Subject: [PATCH 093/160] fixed NPE when trade database has no displayed item --- .../java/com/cubefury/vendingmachine/trade/Trade.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java index 8a3c70b..998f745 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java @@ -28,7 +28,10 @@ public class Trade { public BigItemStack displayItem = new BigItemStack(ItemPlaceholder.placeholder); public NBTTagCompound writeToNBT(NBTTagCompound nbt) { - nbt.setTag("displayItem", displayItem.writeToNBT(new NBTTagCompound())); + nbt.setTag( + "displayItem", + (displayItem != null ? displayItem : new BigItemStack(ItemPlaceholder.placeholder)) + .writeToNBT(new NBTTagCompound())); if (!this.fromCurrency.isEmpty()) { NBTTagList fromCurrencyArray = new NBTTagList(); @@ -66,7 +69,9 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { } public void readFromNBT(NBTTagCompound nbt) { - displayItem = BigItemStack.loadItemStackFromNBT(nbt.getCompoundTag("displayItem")); + if (nbt.hasKey("displayItem")) { + displayItem = BigItemStack.loadItemStackFromNBT(nbt.getCompoundTag("displayItem")); + } fromCurrency.clear(); fromItems.clear(); From bbedd48c79598c9bba86d9bd5cc982f7d6d35d9d Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 6 Nov 2025 17:34:38 +0800 Subject: [PATCH 094/160] Skip displaying cooldown remaining if trade is disabled anyway --- .../vendingmachine/blocks/gui/TradeItemDisplayWidget.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 5125b14..43d19c2 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -155,7 +155,7 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { 0xBB000000); } this.overlay( - IKey.str(display.hasCooldown ? this.display.cooldownText : "") + IKey.str(display.hasCooldown && this.display.enabled ? this.display.cooldownText : "") .style(IKey.WHITE) .scale(0.9f)); } From 1cfdb9ffe0860be161dd1c3362a13a29eda8fc8d Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 6 Nov 2025 17:35:52 +0800 Subject: [PATCH 095/160] actually load the trade count from file --- .../java/com/cubefury/vendingmachine/trade/TradeHistory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java index 537a2c4..bdaaf4f 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java @@ -11,7 +11,7 @@ public TradeHistory() {} public TradeHistory(long lastTrade, int tradeCount) { this.lastTrade = lastTrade; - this.tradeCount = 0; + this.tradeCount = tradeCount; } public void executeTrade() { From 9934b495692e204e11c91b179bbbb907c0125291 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 6 Nov 2025 18:57:19 +0800 Subject: [PATCH 096/160] Address comments --- .../java/com/cubefury/vendingmachine/trade/Trade.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java index 998f745..e347f1d 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/Trade.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java @@ -28,10 +28,7 @@ public class Trade { public BigItemStack displayItem = new BigItemStack(ItemPlaceholder.placeholder); public NBTTagCompound writeToNBT(NBTTagCompound nbt) { - nbt.setTag( - "displayItem", - (displayItem != null ? displayItem : new BigItemStack(ItemPlaceholder.placeholder)) - .writeToNBT(new NBTTagCompound())); + nbt.setTag("displayItem", displayItem.writeToNBT(new NBTTagCompound())); if (!this.fromCurrency.isEmpty()) { NBTTagList fromCurrencyArray = new NBTTagList(); @@ -70,7 +67,8 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { public void readFromNBT(NBTTagCompound nbt) { if (nbt.hasKey("displayItem")) { - displayItem = BigItemStack.loadItemStackFromNBT(nbt.getCompoundTag("displayItem")); + BigItemStack readStack = BigItemStack.loadItemStackFromNBT(nbt.getCompoundTag("displayItem")); + displayItem = readStack == null ? displayItem : readStack; } fromCurrency.clear(); From 1c13c59c460d3ea2c36d6cf9b560bfb47d44b9c3 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 6 Nov 2025 23:14:48 +0800 Subject: [PATCH 097/160] command hint fix --- .../vendingmachine/command/CommandVending.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 446ec79..af9a600 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -14,7 +14,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.util.ChatComponentText; -import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyType; import com.cubefury.vendingmachine.trade.TradeManager; @@ -29,7 +28,7 @@ public String getCommandName() { @Override public String getCommandUsage(ICommandSender sender) { - return "/vending [player] "; + return "/vending [player] [amount]"; } @Override @@ -90,7 +89,6 @@ public void processCommand(ICommandSender sender, String[] args) { String action = args[0]; EntityPlayerMP target = null; - VendingMachine.LOG.info(args.length); if (args.length > 2 && action.equals("reset") || args.length > 3) { target = getPlayer(sender, args[1]); } else if (sender instanceof EntityPlayer) { @@ -118,13 +116,12 @@ public void processCommand(ICommandSender sender, String[] args) { Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); if (args[typeOffset].equals("all")) { for (CurrencyType cur : CurrencyType.values()) { - coinInventory.putIfAbsent(cur, 0); - - coinInventory.put(cur, action.equals("add") ? coinInventory.get(cur) + amount : amount); + coinInventory + .put(cur, action.equals("add") ? coinInventory.getOrDefault(cur, 0) + amount : amount); } } else { - coinInventory.putIfAbsent(type, 0); - coinInventory.put(type, action.equals("add") ? coinInventory.get(type) + amount : amount); + coinInventory + .put(type, action.equals("add") ? coinInventory.getOrDefault(type, 0) + amount : amount); } } catch (NumberFormatException e) { sender.addChatMessage( From fc3db3f9f1e64a4d8ddaf68ef3ce552fd835f692 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 6 Nov 2025 23:28:13 +0800 Subject: [PATCH 098/160] Update readme with commands --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index e91cd13..b236278 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,16 @@ This mod adds a vending machine, unlocking trades based on questbook data. If yo ### Interface ![img_1.png](img_1.png) +### Command + +**Note: All commands require OP to run** + +|Task| Command | +|--|---------------------------------------------------| +|**Set coin**| `/vending set [player] ` | +|**Add coin**| `/vending add [player] ` | +|**Reset coins**| `/vending reset [player] ` + ## Current Status Alpha Testing From 4564b942ffc8a4937f18e4a1cec14cc600f0d324 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 14 Nov 2025 11:10:44 +0800 Subject: [PATCH 099/160] Removed translator class reference from server side. --- .../vendingmachine/command/CommandVending.java | 13 ++++++------- .../resources/assets/vendingmachine/lang/en_US.lang | 5 ----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index af9a600..26c06bc 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -17,7 +17,6 @@ import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyType; import com.cubefury.vendingmachine.trade.TradeManager; -import com.cubefury.vendingmachine.util.Translator; public class CommandVending extends CommandBase { @@ -82,7 +81,7 @@ public void processCommand(ICommandSender sender, String[] args) { if (args.length < 2) { sender.addChatMessage( new ChatComponentText( - Translator.translate("vendingmachine.command.usage") + " " + getCommandUsage(sender))); + "Usage: " + getCommandUsage(sender))); return; } @@ -96,7 +95,7 @@ public void processCommand(ICommandSender sender, String[] args) { } if (target == null) { - sender.addChatMessage(new ChatComponentText(Translator.translate("vendingmachine.command.invalid_player"))); + sender.addChatMessage(new ChatComponentText("Could not identify player.")); return; } @@ -106,7 +105,7 @@ public void processCommand(ICommandSender sender, String[] args) { if (type == null && !args[typeOffset].equals("all")) { sender.addChatMessage( new ChatComponentText( - Translator.translate("vendingmachine.command.unknown_currency") + " " + args[typeOffset])); + "Unknown Currency Type: " + args[typeOffset])); return; } try { @@ -126,7 +125,7 @@ public void processCommand(ICommandSender sender, String[] args) { } catch (NumberFormatException e) { sender.addChatMessage( new ChatComponentText( - Translator.translate("vendingmachine.command.usage") + " " + "Usage: " + getAddOrSetUsage(sender, args[0]))); } } else if (action.equals("reset")) { @@ -135,7 +134,7 @@ public void processCommand(ICommandSender sender, String[] args) { if (type == null && !args[typeOffset].equals("all")) { sender.addChatMessage( new ChatComponentText( - Translator.translate("vendingmachine.command.unknown_currency") + " " + args[typeOffset])); + "Unknown Currency Type: " + args[typeOffset])); return; } UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); @@ -148,7 +147,7 @@ public void processCommand(ICommandSender sender, String[] args) { } } else { sender.addChatMessage( - new ChatComponentText(Translator.translate("vendingmachine.command.unknown_action") + " " + action)); + new ChatComponentText("Unknown Action: " + action)); } } diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index ac80af0..d78d3bc 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -4,11 +4,6 @@ tooltip.vendingmachine=Who's even restocking this... structure.vendingmachine.hint.1=Hint 1 Dot: Tin Item Pipe Casing, ME Vending Uplink Hatch -vendingmachine.command.usage=Usage: -vendingmachine.command.invalid_player=Could not identify player -vendingmachine.command.unknown_action=Unknown action: -vendingmachine.command.unknown_currency=Unknown currency type: - vendingmachine.gui.requirementHeader=Requirements: vendingmachine.gui.requirement.unknown=Unknown Requirement vendingmachine.gui.requirement.betterquesting=Quest From 63c511142baa12b319deb4ad343cbc0718684f15 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 14 Nov 2025 11:11:19 +0800 Subject: [PATCH 100/160] spotless --- .../command/CommandVending.java | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 26c06bc..816405a 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -79,9 +79,7 @@ public List addTabCompletionOptions(ICommandSender sender, String[] args @Override public void processCommand(ICommandSender sender, String[] args) { if (args.length < 2) { - sender.addChatMessage( - new ChatComponentText( - "Usage: " + getCommandUsage(sender))); + sender.addChatMessage(new ChatComponentText("Usage: " + getCommandUsage(sender))); return; } @@ -103,9 +101,7 @@ public void processCommand(ICommandSender sender, String[] args) { int typeOffset = args.length > 3 ? 2 : 1; CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); if (type == null && !args[typeOffset].equals("all")) { - sender.addChatMessage( - new ChatComponentText( - "Unknown Currency Type: " + args[typeOffset])); + sender.addChatMessage(new ChatComponentText("Unknown Currency Type: " + args[typeOffset])); return; } try { @@ -123,18 +119,13 @@ public void processCommand(ICommandSender sender, String[] args) { .put(type, action.equals("add") ? coinInventory.getOrDefault(type, 0) + amount : amount); } } catch (NumberFormatException e) { - sender.addChatMessage( - new ChatComponentText( - "Usage: " - + getAddOrSetUsage(sender, args[0]))); + sender.addChatMessage(new ChatComponentText("Usage: " + getAddOrSetUsage(sender, args[0]))); } } else if (action.equals("reset")) { int typeOffset = args.length > 2 ? 2 : 1; CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); if (type == null && !args[typeOffset].equals("all")) { - sender.addChatMessage( - new ChatComponentText( - "Unknown Currency Type: " + args[typeOffset])); + sender.addChatMessage(new ChatComponentText("Unknown Currency Type: " + args[typeOffset])); return; } UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); @@ -146,8 +137,7 @@ public void processCommand(ICommandSender sender, String[] args) { coinInventory.remove(type); } } else { - sender.addChatMessage( - new ChatComponentText("Unknown Action: " + action)); + sender.addChatMessage(new ChatComponentText("Unknown Action: " + action)); } } From ae36d34fab800272d62742a972419902a2cb8116 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 14 Nov 2025 11:25:30 +0800 Subject: [PATCH 101/160] Added command feedback. --- .../command/CommandVending.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 816405a..566eead 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -114,9 +114,24 @@ public void processCommand(ICommandSender sender, String[] args) { coinInventory .put(cur, action.equals("add") ? coinInventory.getOrDefault(cur, 0) + amount : amount); } + sender.addChatMessage( + new ChatComponentText( + String.format( + "%s %dx all coins for %s", + action.equals("add") ? "Added" : "Set", + amount, + target.getDisplayName()))); } else { coinInventory .put(type, action.equals("add") ? coinInventory.getOrDefault(type, 0) + amount : amount); + sender.addChatMessage( + new ChatComponentText( + String.format( + "%s %dx %s coins for %s", + action.equals("add") ? "Added" : "Set", + amount, + type.id, + target.getDisplayName()))); } } catch (NumberFormatException e) { sender.addChatMessage(new ChatComponentText("Usage: " + getAddOrSetUsage(sender, args[0]))); @@ -133,8 +148,12 @@ public void processCommand(ICommandSender sender, String[] args) { Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); if (args[typeOffset].equals("all")) { coinInventory.clear(); + sender.addChatMessage( + new ChatComponentText(String.format("Reset all coins for %s", target.getDisplayName()))); } else { coinInventory.remove(type); + sender.addChatMessage( + new ChatComponentText(String.format("Reset %s coins for %s", type.id, target.getDisplayName()))); } } else { sender.addChatMessage(new ChatComponentText("Unknown Action: " + action)); From 595887c3323ca27054b04fecaea91baaebe54dae Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 16 Nov 2025 10:41:57 +0800 Subject: [PATCH 102/160] Address Comments --- .../command/CommandVending.java | 73 +++++++++++-------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 566eead..2a58b59 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -32,7 +32,7 @@ public String getCommandUsage(ICommandSender sender) { @Override public int getRequiredPermissionLevel() { - return 2; + return 4; } @Override @@ -98,45 +98,56 @@ public void processCommand(ICommandSender sender, String[] args) { } if (action.equals("set") || action.equals("add")) { + if (args.length < 3 || args.length > 4) { + sender.addChatMessage(new ChatComponentText("Usage: " + getAddOrSetUsage(sender, args[0]))); + return; + } + + int amount = 0; + try { + amount = Integer.parseInt(args[args.length - 1]); + } catch (NumberFormatException e) { + sender.addChatMessage(new ChatComponentText("Usage: " + getAddOrSetUsage(sender, args[0]))); + return; + } + int typeOffset = args.length > 3 ? 2 : 1; CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); if (type == null && !args[typeOffset].equals("all")) { sender.addChatMessage(new ChatComponentText("Unknown Currency Type: " + args[typeOffset])); return; } - try { - int amount = Integer.parseInt(args[typeOffset + 1]); - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); - TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); - Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); - if (args[typeOffset].equals("all")) { - for (CurrencyType cur : CurrencyType.values()) { - coinInventory - .put(cur, action.equals("add") ? coinInventory.getOrDefault(cur, 0) + amount : amount); - } - sender.addChatMessage( - new ChatComponentText( - String.format( - "%s %dx all coins for %s", - action.equals("add") ? "Added" : "Set", - amount, - target.getDisplayName()))); - } else { - coinInventory - .put(type, action.equals("add") ? coinInventory.getOrDefault(type, 0) + amount : amount); - sender.addChatMessage( - new ChatComponentText( - String.format( - "%s %dx %s coins for %s", - action.equals("add") ? "Added" : "Set", - amount, - type.id, - target.getDisplayName()))); + + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); + TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); + if (args[typeOffset].equals("all")) { + for (CurrencyType cur : CurrencyType.values()) { + coinInventory.put(cur, action.equals("add") ? coinInventory.getOrDefault(cur, 0) + amount : amount); } - } catch (NumberFormatException e) { - sender.addChatMessage(new ChatComponentText("Usage: " + getAddOrSetUsage(sender, args[0]))); + sender.addChatMessage( + new ChatComponentText( + String.format( + "%s %dx all coins for %s", + action.equals("add") ? "Added" : "Set", + amount, + target.getDisplayName()))); + } else { + coinInventory.put(type, action.equals("add") ? coinInventory.getOrDefault(type, 0) + amount : amount); + sender.addChatMessage( + new ChatComponentText( + String.format( + "%s %dx %s coins for %s", + action.equals("add") ? "Added" : "Set", + amount, + type.id, + target.getDisplayName()))); } } else if (action.equals("reset")) { + if (args.length < 2 || args.length > 3) { + sender.addChatMessage(new ChatComponentText("Usage: /vending reset [player] [coin_type|all]")); + return; + } int typeOffset = args.length > 2 ? 2 : 1; CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); if (type == null && !args[typeOffset].equals("all")) { From 7ffe5c48c331f8202c16969214b4f2d3726963ab Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 16 Nov 2025 11:04:09 +0800 Subject: [PATCH 103/160] - Improved command tab completion hint to not populate coin twice. - Fixed bug where spamming tab at command hint would crash the game due to PlayerNotFoundException. - Removed redundant condition check. --- .../vendingmachine/command/CommandVending.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 2a58b59..a395162 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -9,6 +9,7 @@ import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; +import net.minecraft.command.PlayerNotFoundException; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; @@ -59,6 +60,12 @@ public List addTabCompletionOptions(ICommandSender sender, String[] args return suggestions; } case 3: { + try { + getPlayer(sender, args[1]); + } catch (PlayerNotFoundException except) { + return null; + } + List suggestions = Arrays.stream(CurrencyType.values()) .map(c -> c.id) .collect(Collectors.toList()); @@ -87,7 +94,9 @@ public void processCommand(ICommandSender sender, String[] args) { EntityPlayerMP target = null; if (args.length > 2 && action.equals("reset") || args.length > 3) { - target = getPlayer(sender, args[1]); + try { + target = getPlayer(sender, args[1]); + } catch (PlayerNotFoundException ignored) {} } else if (sender instanceof EntityPlayer) { target = getCommandSenderAsPlayer(sender); } @@ -144,7 +153,7 @@ public void processCommand(ICommandSender sender, String[] args) { target.getDisplayName()))); } } else if (action.equals("reset")) { - if (args.length < 2 || args.length > 3) { + if (args.length > 3) { sender.addChatMessage(new ChatComponentText("Usage: /vending reset [player] [coin_type|all]")); return; } From 58cff9b25593ef1988728efb46b60639db3d81ac Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 16 Nov 2025 14:46:09 +0800 Subject: [PATCH 104/160] Address comments. --- .../com/cubefury/vendingmachine/command/CommandVending.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index a395162..dbf3fbc 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -31,11 +31,6 @@ public String getCommandUsage(ICommandSender sender) { return "/vending [player] [amount]"; } - @Override - public int getRequiredPermissionLevel() { - return 4; - } - @Override public boolean canCommandSenderUseCommand(ICommandSender sender) { return sender.canCommandSenderUseCommand(getRequiredPermissionLevel(), getCommandName()); From d0aa702b842c17797003742cd87d713dd05dbf07 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 19 Nov 2025 20:40:37 +0800 Subject: [PATCH 105/160] Fix tile data saving. --- .../com/cubefury/vendingmachine/blocks/MTEVendingMachine.java | 2 ++ .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 7e767fd..b346aa7 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -236,6 +236,7 @@ public void dispenseItems() { } ticksSinceOutput = this.newBufferedOutputs ? 0 : ticksSinceOutput + 1; this.newBufferedOutputs = false; + this.markDirty(); } private boolean processTradeOnServer(TradeRequest tradeRequest) { @@ -331,6 +332,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { .get(tradeRequest.tradeGroup) .executeTrade(tradeRequest.playerID); this.sendTradeUpdate(); + this.markDirty(); 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 02798a3..83131d4 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -429,6 +429,7 @@ private SlotGroupWidget createInputSlots() { if (hasCoin) { this.refreshInputSlots(); } + base.markDirty(); })); }) .build(); @@ -440,7 +441,8 @@ private SlotGroupWidget createOutputSlots() { .key('I', index -> { return new ItemSlot().slot( new ModularSlot(base.outputItems, index).accessibility(false, true) - .slotGroup("outputSlotGroup")); + .slotGroup("outputSlotGroup") + .changeListener((newitem, onlyAmountChanged, client, init) -> { base.markDirty(); })); }) .build(); } From 533ec5cac0d9394a1d783732706ac8c17d0ab8c7 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 24 Nov 2025 23:55:52 +0800 Subject: [PATCH 106/160] ego stroking --- .../java/com/cubefury/vendingmachine/VendingMachine.java | 8 ++++++++ .../cubefury/vendingmachine/blocks/MTEVendingMachine.java | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java index 89346c5..82d7774 100644 --- a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java @@ -1,5 +1,7 @@ package com.cubefury.vendingmachine; +import net.minecraft.util.EnumChatFormatting; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -39,6 +41,12 @@ public class VendingMachine { public static final Logger LOG = LogManager.getLogger(MODID); public static final String CHANNEL = "VM_NET_CHAN"; public static final String NAME = "Vending Machine"; + public static final String AUTHOR_CUBEFURY = "Author: " + EnumChatFormatting.AQUA + + EnumChatFormatting.BOLD + + "Cube" + + EnumChatFormatting.BLUE + + EnumChatFormatting.BOLD + + "Fury"; @Mod.Instance(MODID) public static VendingMachine instance; diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index b346aa7..407476f 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -1,5 +1,6 @@ package com.cubefury.vendingmachine.blocks; +import static com.cubefury.vendingmachine.VendingMachine.AUTHOR_CUBEFURY; import static com.cubefury.vendingmachine.api.enums.Textures.VM_MACHINE_FRONT_OFF; import static com.cubefury.vendingmachine.api.enums.Textures.VM_MACHINE_FRONT_ON; import static com.cubefury.vendingmachine.api.enums.Textures.VM_MACHINE_FRONT_ON_GLOW; @@ -370,7 +371,7 @@ protected MultiblockTooltipBuilder getTooltip() { .addOtherStructurePart("Tin Item Pipe Casings", "Everything except the controller") .addOtherStructurePart("ME Vending Uplink Hatch", "Any Pipe Casing, Optional") .addStructureInfo("Cannot be flipped onto its side") - .toolTipFinisher(); + .toolTipFinisher(AUTHOR_CUBEFURY); } return tooltipBuilder; } From 3f3bb39d4703e53d8308dd3f8568e040114ca96b Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 25 Nov 2025 18:50:19 +0800 Subject: [PATCH 107/160] update deps --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 56d5159..2661237 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -35,7 +35,7 @@ */ dependencies { implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.26-GTNH:dev") - implementation("com.github.GTNewHorizons:GTNHLib:0.7.7:dev") + implementation("com.github.GTNewHorizons:GTNHLib:0.8.13:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.5-1.7.10:dev") From b7a2b14aab615a3ae56ac1297b1fa3c555a3e40b Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 25 Nov 2025 20:13:36 +0800 Subject: [PATCH 108/160] change config class name --- .../com/cubefury/vendingmachine/CommonProxy.java | 2 +- .../{Config.java => VMConfig.java} | 2 +- .../vendingmachine/blocks/MTEVendingMachine.java | 10 +++++----- .../blocks/gui/MTEVendingMachineGui.java | 6 +++--- .../blocks/gui/TradeMainPanel.java | 4 ++-- .../vendingmachine/handlers/SaveLoadHandler.java | 16 ++++++++-------- .../vendingmachine/trade/TradeDatabase.java | 4 ++-- 7 files changed, 22 insertions(+), 22 deletions(-) rename src/main/java/com/cubefury/vendingmachine/{Config.java => VMConfig.java} (99%) diff --git a/src/main/java/com/cubefury/vendingmachine/CommonProxy.java b/src/main/java/com/cubefury/vendingmachine/CommonProxy.java index 51c4af4..59efddc 100644 --- a/src/main/java/com/cubefury/vendingmachine/CommonProxy.java +++ b/src/main/java/com/cubefury/vendingmachine/CommonProxy.java @@ -21,7 +21,7 @@ public class CommonProxy { // GameRegistry." (Remove if not needed) public void preInit(FMLPreInitializationEvent event) { VendingMachine.LOG.info("Loading Vending Machine " + Tags.VERSION); - Config.init(event.getSuggestedConfigurationFile()); + VMConfig.init(event.getSuggestedConfigurationFile()); } // load "Do your mod setup. Build whatever data structures you care about. Register recipes." (Remove if not needed) diff --git a/src/main/java/com/cubefury/vendingmachine/Config.java b/src/main/java/com/cubefury/vendingmachine/VMConfig.java similarity index 99% rename from src/main/java/com/cubefury/vendingmachine/Config.java rename to src/main/java/com/cubefury/vendingmachine/VMConfig.java index a208507..d8b22cd 100644 --- a/src/main/java/com/cubefury/vendingmachine/Config.java +++ b/src/main/java/com/cubefury/vendingmachine/VMConfig.java @@ -7,7 +7,7 @@ import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplayWidget.DisplayType; -public class Config { +public class VMConfig { private static final String CONFIG_CATEGORY_VM = "Vending Machine Settings"; private static final String CONFIG_CATEGORY_DEVELOPER = "Developer Settings"; diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 407476f..4289085 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -34,7 +34,7 @@ import org.lwjgl.input.Keyboard; import com.cleanroommc.modularui.utils.item.ItemStackHandler; -import com.cubefury.vendingmachine.Config; +import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplay; @@ -181,9 +181,9 @@ public void dispenseItems() { } if ( this.newBufferedOutputs - || (!this.outputBuffer.isEmpty() && this.ticksSinceOutput % Config.dispense_frequency == 0) + || (!this.outputBuffer.isEmpty() && this.ticksSinceOutput % VMConfig.dispense_frequency == 0) ) { - int remainingDispensables = Config.dispense_amount; + int remainingDispensables = VMConfig.dispense_amount; while (!this.outputBuffer.isEmpty() && remainingDispensables > 0) { ItemStack next = this.outputBuffer.peek(); @@ -552,7 +552,7 @@ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { } if (aBaseMetaTileEntity.isServerSide()) { dispenseItems(); - if (this.getActive() && this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { + if (this.getActive() && this.ticksSinceTradeUpdate++ >= VMConfig.gui_refresh_interval) { this.sendTradeUpdate(); } if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { @@ -693,7 +693,7 @@ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlaye if (canUse(aPlayer)) { this.currentUser = aPlayer; // force trade state update now - this.ticksSinceTradeUpdate = Config.gui_refresh_interval; + this.ticksSinceTradeUpdate = VMConfig.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/MTEVendingMachineGui.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java index 83131d4..b6ba8be 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -41,7 +41,7 @@ import com.cleanroommc.modularui.widgets.layout.Row; import com.cleanroommc.modularui.widgets.slot.ItemSlot; import com.cleanroommc.modularui.widgets.slot.ModularSlot; -import com.cubefury.vendingmachine.Config; +import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.gui.GuiTextures; @@ -80,8 +80,8 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { public static String lastSearch = ""; public static int lastPage = 0; - public static TradeItemDisplayWidget.DisplayType displayType = Config.display_type; - public static SortMode sortMode = Config.sort_mode; + public static TradeItemDisplayWidget.DisplayType displayType = VMConfig.display_type; + public static SortMode sortMode = VMConfig.sort_mode; public static final int CUSTOM_UI_HEIGHT = 320; 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 37cbccc..d7671f0 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -17,7 +17,7 @@ import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.ModularScreen; import com.cleanroommc.modularui.value.sync.PanelSyncManager; -import com.cubefury.vendingmachine.Config; +import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.network.handlers.NetResetVMUser; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; @@ -107,7 +107,7 @@ public void onUpdate() { MTEVendingMachineGui.setForceRefresh(); } if ( - MTEVendingMachineGui.forceRefresh || (this.ticksOpen % Config.gui_refresh_interval == 0 && player != null) + MTEVendingMachineGui.forceRefresh || (this.ticksOpen % VMConfig.gui_refresh_interval == 0 && player != null) ) { updateGui(); MTEVendingMachineGui.resetForceRefresh(); diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 89fda28..c2195fb 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -16,7 +16,7 @@ import net.minecraft.nbt.NBTTagList; import net.minecraft.server.MinecraftServer; -import com.cubefury.vendingmachine.Config; +import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.TradeDatabase; @@ -37,15 +37,15 @@ private SaveLoadHandler() {} public void init(MinecraftServer server) { if (VendingMachine.proxy.isClient()) { - Config.worldDir = server.getFile("saves/" + server.getFolderName() + "/" + Config.data_dir); + VMConfig.worldDir = server.getFile("saves/" + server.getFolderName() + "/" + VMConfig.data_dir); } else { - Config.worldDir = server.getFile(server.getFolderName() + "/" + Config.data_dir); + VMConfig.worldDir = server.getFile(server.getFolderName() + "/" + VMConfig.data_dir); } - fileDatabase = new File(Config.config_dir, "tradeDatabase.json"); - dirTradeState = new File(Config.worldDir, "tradeState"); - dirBackupTradeState = new File(Config.worldDir, "backup/tradeState"); - fileNames = new File(Config.worldDir, "names.json"); + fileDatabase = new File(VMConfig.config_dir, "tradeDatabase.json"); + dirTradeState = new File(VMConfig.worldDir, "tradeState"); + dirBackupTradeState = new File(VMConfig.worldDir, "backup/tradeState"); + fileNames = new File(VMConfig.worldDir, "names.json"); createFilesAndDirectories(); @@ -76,7 +76,7 @@ public void loadDatabase() { } public Future writeDatabase() { - CopyPaste(fileDatabase, new File(Config.config_dir + "/backup", "tradeDatabase.json")); + CopyPaste(fileDatabase, new File(VMConfig.config_dir + "/backup", "tradeDatabase.json")); return FileIO.WriteToFile( fileDatabase, out -> NBTConverter.NBTtoJSON_Compound(TradeDatabase.INSTANCE.writeToNBT(new NBTTagCompound()), out, true)); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 4a4ca50..cc43c66 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -15,7 +15,7 @@ import net.minecraft.nbt.NBTTagList; import net.minecraftforge.common.util.Constants; -import com.cubefury.vendingmachine.Config; +import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.integration.betterquesting.BqAdapter; import com.cubefury.vendingmachine.integration.nei.NeiRecipeCache; @@ -98,7 +98,7 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge, boolean isFileLoad) { tradeGroups.put(tg.getId(), tg); } - if (isFileLoad && (Config.forceRewriteDatabase || newMetadataCount > 0)) { + if (isFileLoad && (VMConfig.forceRewriteDatabase || newMetadataCount > 0)) { VendingMachine.LOG.info("Appended metadata to {} new trades", newMetadataCount); DirtyDbMarker.markDirty(); } From e2369bc47f766011e50e064461cd14c373a7be2a Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 25 Nov 2025 21:02:22 +0800 Subject: [PATCH 109/160] Convert to GTNHLib config format --- .../cubefury/vendingmachine/CommonProxy.java | 1 - .../com/cubefury/vendingmachine/VMConfig.java | 127 ++++++++---------- .../vendingmachine/VendingMachine.java | 11 ++ .../blocks/MTEVendingMachine.java | 12 +- .../blocks/gui/MTEVendingMachineGui.java | 4 +- .../blocks/gui/TradeMainPanel.java | 3 +- .../gui/client/VMGuiClientConfig.java | 15 +++ .../gui/client/VMGuiFactory.java | 13 ++ .../handlers/SaveLoadHandler.java | 14 +- .../vendingmachine/trade/TradeDatabase.java | 2 +- 10 files changed, 117 insertions(+), 85 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiClientConfig.java create mode 100644 src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiFactory.java diff --git a/src/main/java/com/cubefury/vendingmachine/CommonProxy.java b/src/main/java/com/cubefury/vendingmachine/CommonProxy.java index 59efddc..ebd74a5 100644 --- a/src/main/java/com/cubefury/vendingmachine/CommonProxy.java +++ b/src/main/java/com/cubefury/vendingmachine/CommonProxy.java @@ -21,7 +21,6 @@ public class CommonProxy { // GameRegistry." (Remove if not needed) public void preInit(FMLPreInitializationEvent event) { VendingMachine.LOG.info("Loading Vending Machine " + Tags.VERSION); - VMConfig.init(event.getSuggestedConfigurationFile()); } // load "Do your mod setup. Build whatever data structures you care about. Register recipes." (Remove if not needed) diff --git a/src/main/java/com/cubefury/vendingmachine/VMConfig.java b/src/main/java/com/cubefury/vendingmachine/VMConfig.java index d8b22cd..cc5e22a 100644 --- a/src/main/java/com/cubefury/vendingmachine/VMConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/VMConfig.java @@ -2,78 +2,69 @@ import java.io.File; -import net.minecraftforge.common.config.Configuration; - import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplayWidget.DisplayType; +import com.gtnewhorizon.gtnhlib.config.Config; +@Config(modid = VendingMachine.MODID, category = "vendingmachine", filename = "vendingmachine") public class VMConfig { - private static final String CONFIG_CATEGORY_VM = "Vending Machine Settings"; - private static final String CONFIG_CATEGORY_DEVELOPER = "Developer Settings"; - - public static String data_dir = "vendingmachine"; - public static String config_dir = "config/vendingmachine"; - public static int gui_refresh_interval = 20; - public static int dispense_frequency = 10; - public static int dispense_amount = 16; - public static DisplayType display_type = DisplayType.TILE; - public static MTEVendingMachineGui.SortMode sort_mode = MTEVendingMachineGui.SortMode.SMART; - public static boolean forceRewriteDatabase = false; - - public static File worldDir = null; - - public static void init(File configFile) { - Configuration configuration = new Configuration(configFile); - - data_dir = configuration - .getString("data_dir", Configuration.CATEGORY_GENERAL, data_dir, "World vendingmachine data directory"); - config_dir = configuration - .getString("config_dir", Configuration.CATEGORY_GENERAL, config_dir, "Configuration directory"); - - configuration.addCustomCategoryComment(CONFIG_CATEGORY_VM, "Vending Machine Settings"); - gui_refresh_interval = configuration - .getInt("gui_refresh_interval", CONFIG_CATEGORY_VM, gui_refresh_interval, 20, 3600, "In number of ticks"); - dispense_frequency = configuration - .getInt("dispense_frequency", CONFIG_CATEGORY_VM, dispense_frequency, 1, 9000, "In number of ticks"); - dispense_amount = configuration.getInt( - "dispense_amount", - CONFIG_CATEGORY_VM, - dispense_amount, - 1, - Integer.MAX_VALUE, - "Number of items per dispense cycle"); - - configuration.addCustomCategoryComment(CONFIG_CATEGORY_DEVELOPER, "Developer Settings"); - forceRewriteDatabase = configuration.getBoolean( - "force_rewrite_database", - CONFIG_CATEGORY_DEVELOPER, - forceRewriteDatabase, - "Force rewrite database on load, for add/remove trades or change of format"); - - try { - display_type = DisplayType.valueOf( - configuration.getString( - "display_type", - CONFIG_CATEGORY_VM, - "TILE", - "Default trade display format, either TILE or LIST. Case sensitive.")); - } catch (IllegalArgumentException e) { - display_type = DisplayType.TILE; - } - try { - sort_mode = MTEVendingMachineGui.SortMode.valueOf( - configuration.getString( - "sort_mode", - CONFIG_CATEGORY_VM, - "SMART", - "Default sort mode, either SMART or ALPHABET. Case sensitive.")); - } catch (IllegalArgumentException e) { - sort_mode = MTEVendingMachineGui.SortMode.SMART; - } - - if (configuration.hasChanged()) { - configuration.save(); - } + @Config.Comment("Vending Machine Settings") + public static final VendingMachineSettings vendingMachineSettings = new VendingMachineSettings(); + + @Config.Comment("GUI Settings") + public static final GUI gui = new GUI(); + + @Config.Comment("Developer Settings") + public static final Developer developer = new Developer(); + + public static class VendingMachineSettings { + + @Config.Comment("How often the vending machine refreshes its data, in number of ticks") + @Config.DefaultInt(20) + @Config.RequiresWorldRestart + public int gui_refresh_interval; + + @Config.Comment("How often items items are ejected, in number of ticks") + @Config.DefaultInt(10) + @Config.RequiresWorldRestart + public int dispense_frequency; + + @Config.Comment("How many items are dispensed from the queue at once") + @Config.DefaultInt(16) + @Config.RequiresWorldRestart + public int dispense_amount; } + + public static class GUI { + + @Config.Comment("Default trade display format, either TILE or LIST. Case sensitive.") + @Config.DefaultEnum("TILE") + public DisplayType display_type = DisplayType.TILE; + + @Config.Comment("Default sort mode, either SMART or ALPHABET. Case sensitive.") + @Config.DefaultEnum("SMART") + public MTEVendingMachineGui.SortMode sort_mode = MTEVendingMachineGui.SortMode.SMART; + } + + public static class Developer { + + @Config.Comment("subdirectory for vending machine data in world save") + @Config.DefaultString("vendingmachine") + @Config.RequiresMcRestart + public String data_dir; + + @Config.Comment("folder where trade database file is located") + @Config.DefaultString("config/vendingmachine") + @Config.RequiresMcRestart + public String trade_db_dir = "config/vendingmachine"; + + @Config.Comment("Force rewrite database on load, for add/remove trades or change of format") + @Config.DefaultBoolean(false) + @Config.RequiresWorldRestart + public boolean force_rewrite_database = false; + } + + @Config.Ignore + public static File world_dir = null; } diff --git a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java index 82d7774..cf59fee 100644 --- a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java @@ -12,6 +12,8 @@ import com.cubefury.vendingmachine.network.SerializedPacket; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.util.ItemPlaceholder; +import com.gtnewhorizon.gtnhlib.config.ConfigException; +import com.gtnewhorizon.gtnhlib.config.ConfigurationManager; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.Mod; @@ -34,9 +36,18 @@ modid = VendingMachine.MODID, version = Tags.VERSION, name = VendingMachine.NAME, + guiFactory = "com.cubefury.vendingmachine.gui.client.VMGuiFactory", acceptedMinecraftVersions = "[1.7.10]") public class VendingMachine { + static { + try { + ConfigurationManager.registerConfig(VMConfig.class); + } catch (ConfigException e) { + throw new RuntimeException(e); + } + } + public static final String MODID = "vendingmachine"; public static final Logger LOG = LogManager.getLogger(MODID); public static final String CHANNEL = "VM_NET_CHAN"; diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 4289085..0e06c63 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -180,10 +180,10 @@ public void dispenseItems() { NetTradeRequestSync.sendAck(tradeRequest.player); } if ( - this.newBufferedOutputs - || (!this.outputBuffer.isEmpty() && this.ticksSinceOutput % VMConfig.dispense_frequency == 0) + this.newBufferedOutputs || (!this.outputBuffer.isEmpty() + && this.ticksSinceOutput % VMConfig.vendingMachineSettings.dispense_frequency == 0) ) { - int remainingDispensables = VMConfig.dispense_amount; + int remainingDispensables = VMConfig.vendingMachineSettings.dispense_amount; while (!this.outputBuffer.isEmpty() && remainingDispensables > 0) { ItemStack next = this.outputBuffer.peek(); @@ -552,7 +552,9 @@ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { } if (aBaseMetaTileEntity.isServerSide()) { dispenseItems(); - if (this.getActive() && this.ticksSinceTradeUpdate++ >= VMConfig.gui_refresh_interval) { + if ( + this.getActive() && this.ticksSinceTradeUpdate++ >= VMConfig.vendingMachineSettings.gui_refresh_interval + ) { this.sendTradeUpdate(); } if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { @@ -693,7 +695,7 @@ public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlaye if (canUse(aPlayer)) { this.currentUser = aPlayer; // force trade state update now - this.ticksSinceTradeUpdate = VMConfig.gui_refresh_interval; + this.ticksSinceTradeUpdate = VMConfig.vendingMachineSettings.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/MTEVendingMachineGui.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java index b6ba8be..e6e3fab 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -80,8 +80,8 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { public static String lastSearch = ""; public static int lastPage = 0; - public static TradeItemDisplayWidget.DisplayType displayType = VMConfig.display_type; - public static SortMode sortMode = VMConfig.sort_mode; + public static TradeItemDisplayWidget.DisplayType displayType = VMConfig.gui.display_type; + public static SortMode sortMode = VMConfig.gui.sort_mode; public static final int CUSTOM_UI_HEIGHT = 320; 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 d7671f0..8adb28c 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -107,7 +107,8 @@ public void onUpdate() { MTEVendingMachineGui.setForceRefresh(); } if ( - MTEVendingMachineGui.forceRefresh || (this.ticksOpen % VMConfig.gui_refresh_interval == 0 && player != null) + MTEVendingMachineGui.forceRefresh + || (this.ticksOpen % VMConfig.vendingMachineSettings.gui_refresh_interval == 0 && player != null) ) { updateGui(); MTEVendingMachineGui.resetForceRefresh(); diff --git a/src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiClientConfig.java b/src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiClientConfig.java new file mode 100644 index 0000000..e5b6d45 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiClientConfig.java @@ -0,0 +1,15 @@ +package com.cubefury.vendingmachine.gui.client; + +import net.minecraft.client.gui.GuiScreen; + +import com.cubefury.vendingmachine.VMConfig; +import com.cubefury.vendingmachine.VendingMachine; +import com.gtnewhorizon.gtnhlib.config.ConfigException; +import com.gtnewhorizon.gtnhlib.config.SimpleGuiConfig; + +public class VMGuiClientConfig extends SimpleGuiConfig { + + public VMGuiClientConfig(GuiScreen parentScreen) throws ConfigException { + super(parentScreen, VendingMachine.MODID, VendingMachine.NAME, true, VMConfig.class); + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiFactory.java b/src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiFactory.java new file mode 100644 index 0000000..4aff084 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/gui/client/VMGuiFactory.java @@ -0,0 +1,13 @@ +package com.cubefury.vendingmachine.gui.client; + +import net.minecraft.client.gui.GuiScreen; + +import com.gtnewhorizon.gtnhlib.config.SimpleGuiFactory; + +public class VMGuiFactory implements SimpleGuiFactory { + + @Override + public Class mainConfigGuiClass() { + return VMGuiClientConfig.class; + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index c2195fb..3f6cbdc 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -37,15 +37,15 @@ private SaveLoadHandler() {} public void init(MinecraftServer server) { if (VendingMachine.proxy.isClient()) { - VMConfig.worldDir = server.getFile("saves/" + server.getFolderName() + "/" + VMConfig.data_dir); + VMConfig.world_dir = server.getFile("saves/" + server.getFolderName() + "/" + VMConfig.developer.data_dir); } else { - VMConfig.worldDir = server.getFile(server.getFolderName() + "/" + VMConfig.data_dir); + VMConfig.world_dir = server.getFile(server.getFolderName() + "/" + VMConfig.developer.data_dir); } - fileDatabase = new File(VMConfig.config_dir, "tradeDatabase.json"); - dirTradeState = new File(VMConfig.worldDir, "tradeState"); - dirBackupTradeState = new File(VMConfig.worldDir, "backup/tradeState"); - fileNames = new File(VMConfig.worldDir, "names.json"); + fileDatabase = new File(VMConfig.developer.trade_db_dir, "tradeDatabase.json"); + dirTradeState = new File(VMConfig.world_dir, "tradeState"); + dirBackupTradeState = new File(VMConfig.world_dir, "backup/tradeState"); + fileNames = new File(VMConfig.world_dir, "names.json"); createFilesAndDirectories(); @@ -76,7 +76,7 @@ public void loadDatabase() { } public Future writeDatabase() { - CopyPaste(fileDatabase, new File(VMConfig.config_dir + "/backup", "tradeDatabase.json")); + CopyPaste(fileDatabase, new File(VMConfig.developer.trade_db_dir + "/backup", "tradeDatabase.json")); return FileIO.WriteToFile( fileDatabase, out -> NBTConverter.NBTtoJSON_Compound(TradeDatabase.INSTANCE.writeToNBT(new NBTTagCompound()), out, true)); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index cc43c66..74b0e1e 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -98,7 +98,7 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge, boolean isFileLoad) { tradeGroups.put(tg.getId(), tg); } - if (isFileLoad && (VMConfig.forceRewriteDatabase || newMetadataCount > 0)) { + if (isFileLoad && (VMConfig.developer.force_rewrite_database || newMetadataCount > 0)) { VendingMachine.LOG.info("Appended metadata to {} new trades", newMetadataCount); DirtyDbMarker.markDirty(); } From 66c49c42b43537218865e5ca0abfbedbdea7fa42 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 25 Nov 2025 21:09:38 +0800 Subject: [PATCH 110/160] Update config file on the fly when gui settings are changed --- .../blocks/gui/MTEVendingMachineGui.java | 31 +++++++++++-------- .../blocks/gui/TradeMainPanel.java | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) 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 e6e3fab..7348ced 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -55,6 +55,7 @@ import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.BigItemStack; import com.cubefury.vendingmachine.util.Translator; +import com.gtnewhorizon.gtnhlib.config.ConfigurationManager; import gregtech.api.modularui2.GTGuiTextures; import gregtech.api.modularui2.GTWidgetThemes; @@ -80,7 +81,6 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { public static String lastSearch = ""; public static int lastPage = 0; - public static TradeItemDisplayWidget.DisplayType displayType = VMConfig.gui.display_type; public static SortMode sortMode = VMConfig.gui.sort_mode; public static final int CUSTOM_UI_HEIGHT = 320; @@ -202,17 +202,18 @@ public IWidget createQolButtonColumn() { new CycleButtonWidget().size(14) .overlay( new DynamicDrawable( - () -> displayType.getTexture() + () -> VMConfig.gui.display_type.getTexture() .size(14))) .stateCount(TradeItemDisplayWidget.DisplayType.values().length) - .value( - new IntValue.Dynamic( - () -> displayType.ordinal(), - val -> { displayType = TradeItemDisplayWidget.DisplayType.values()[val]; })) + .value(new IntValue.Dynamic(() -> VMConfig.gui.display_type.ordinal(), val -> { + VMConfig.gui.display_type = TradeItemDisplayWidget.DisplayType.values()[val]; + ConfigurationManager.save(VMConfig.class); + })) .tooltipDynamic(builder -> { builder.clearText(); - builder - .addLine(IKey.lang("vendingmachine.gui.display_mode") + " " + displayType.getLocalizedName()); + builder.addLine( + IKey.lang("vendingmachine.gui.display_mode") + " " + + VMConfig.gui.display_type.getLocalizedName()); }) .tooltipAutoUpdate(true)); buttonColumn.child( @@ -220,13 +221,17 @@ public IWidget createQolButtonColumn() { .top(17) .overlay( new DynamicDrawable( - () -> sortMode.getTexture() + () -> VMConfig.gui.sort_mode.getTexture() .size(14))) .stateCount(SortMode.values().length) - .value(new IntValue.Dynamic(() -> sortMode.ordinal(), val -> { sortMode = SortMode.values()[val]; })) + .value(new IntValue.Dynamic(() -> VMConfig.gui.sort_mode.ordinal(), val -> { + VMConfig.gui.sort_mode = SortMode.values()[val]; + ConfigurationManager.save(VMConfig.class); + })) .tooltipDynamic(builder -> { builder.clearText(); - builder.addLine(IKey.lang("vendingmachine.gui.display_sort") + " " + sortMode.getLocalizedName()); + builder.addLine( + IKey.lang("vendingmachine.gui.display_sort") + " " + VMConfig.gui.sort_mode.getLocalizedName()); setForceRefresh(); }) .tooltipAutoUpdate(true)); @@ -536,7 +541,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t .tooltipAutoUpdate(true) .setEnabledIf(slot -> { TradeItemDisplayWidget display = ((TradeItemDisplayWidget) slot); - return displayType == display.displayType && display.getDisplay() != null; + return VMConfig.gui.display_type == display.displayType && display.getDisplay() != null; }) .margin(2)); if (i % TILE_ITEMS_PER_ROW == TILE_ITEMS_PER_ROW - 1) { @@ -566,7 +571,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t .tooltipAutoUpdate(true) .setEnabledIf(slot -> { TradeItemDisplayWidget display = ((TradeItemDisplayWidget) slot); - return displayType == display.displayType && display.getDisplay() != null; + return VMConfig.gui.display_type == display.displayType && display.getDisplay() != null; })); tradeList.child(row); row = new TradeRow().height(LIST_ITEM_HEIGHT).width(TRADE_ROW_WIDTH).marginLeft(2); 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 8adb28c..8d787cc 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -127,7 +127,7 @@ public ItemStack convertToItemStack(BigItemStack stack) { public Map> formatTrades() { Map> trades = new HashMap<>(); trades.put(TradeCategory.ALL, new ArrayList<>()); - MTEVendingMachineGui.SortMode sortMode = MTEVendingMachineGui.sortMode; + MTEVendingMachineGui.SortMode sortMode = VMConfig.gui.sort_mode; for (TradeItemDisplay tid : TradeManager.INSTANCE.tradeData) { TradeGroup group = TradeDatabase.INSTANCE.getTradeGroupFromId(tid.tgID); From 297ab7322f568f649f61aeefb7308ee80284f859 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 13 Dec 2025 12:14:47 +0800 Subject: [PATCH 111/160] Extract display type to separate class --- .../com/cubefury/vendingmachine/VMConfig.java | 2 +- .../blocks/gui/DisplayType.java | 31 +++++++++++++++++++ .../blocks/gui/MTEVendingMachineGui.java | 8 ++--- .../blocks/gui/TradeItemDisplayWidget.java | 28 ----------------- 4 files changed, 36 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java diff --git a/src/main/java/com/cubefury/vendingmachine/VMConfig.java b/src/main/java/com/cubefury/vendingmachine/VMConfig.java index cc5e22a..cbd701a 100644 --- a/src/main/java/com/cubefury/vendingmachine/VMConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/VMConfig.java @@ -3,7 +3,7 @@ import java.io.File; import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; -import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplayWidget.DisplayType; +import com.cubefury.vendingmachine.blocks.gui.DisplayType; import com.gtnewhorizon.gtnhlib.config.Config; @Config(modid = VendingMachine.MODID, category = "vendingmachine", filename = "vendingmachine") diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java new file mode 100644 index 0000000..d6704fd --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java @@ -0,0 +1,31 @@ +package com.cubefury.vendingmachine.blocks.gui; + +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.drawable.Icon; +import com.cleanroommc.modularui.drawable.UITexture; + +import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_LIST; +import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_TILE; + +public enum DisplayType { + + TILE("tile", MODE_TILE), + LIST("list", MODE_LIST); + + private final String type; + private final Icon texture; + + DisplayType(String type, UITexture texture) { + this.type = type; + this.texture = texture.asIcon(); + } + + public String getLocalizedName() { + return IKey.lang("vendingmachine.gui.display_mode_" + this.type) + .toString(); + } + + public Icon getTexture() { + return this.texture; + } +} 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 7348ced..6c5cbb4 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -134,12 +134,12 @@ public MTEVendingMachineGui(MTEVendingMachine base) { displayedTradesTiles.put(c, new ArrayList<>(MTEVendingMachine.MAX_TRADES)); for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { displayedTradesTiles.get(c) - .add(new TradeItemDisplayWidget(null, this.base, TradeItemDisplayWidget.DisplayType.TILE)); + .add(new TradeItemDisplayWidget(null, this.base, DisplayType.TILE)); } displayedTradesList.put(c, new ArrayList<>(MTEVendingMachine.MAX_TRADES)); for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { displayedTradesList.get(c) - .add(new TradeItemDisplayWidget(null, this.base, TradeItemDisplayWidget.DisplayType.LIST)); + .add(new TradeItemDisplayWidget(null, this.base, DisplayType.LIST)); } } @@ -204,9 +204,9 @@ public IWidget createQolButtonColumn() { new DynamicDrawable( () -> VMConfig.gui.display_type.getTexture() .size(14))) - .stateCount(TradeItemDisplayWidget.DisplayType.values().length) + .stateCount(DisplayType.values().length) .value(new IntValue.Dynamic(() -> VMConfig.gui.display_type.ordinal(), val -> { - VMConfig.gui.display_type = TradeItemDisplayWidget.DisplayType.values()[val]; + VMConfig.gui.display_type = DisplayType.values()[val]; ConfigurationManager.save(VMConfig.class); })) .tooltipDynamic(builder -> { diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 43d19c2..f8da553 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -1,8 +1,5 @@ package com.cubefury.vendingmachine.blocks.gui; -import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_LIST; -import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_TILE; - import net.minecraft.item.ItemStack; import org.jetbrains.annotations.NotNull; @@ -12,8 +9,6 @@ import com.cleanroommc.modularui.api.widget.Interactable; import com.cleanroommc.modularui.drawable.DynamicDrawable; import com.cleanroommc.modularui.drawable.GuiDraw; -import com.cleanroommc.modularui.drawable.Icon; -import com.cleanroommc.modularui.drawable.UITexture; import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; import com.cleanroommc.modularui.theme.WidgetThemeEntry; import com.cleanroommc.modularui.utils.Platform; @@ -27,29 +22,6 @@ public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { - public enum DisplayType { - - TILE("tile", MODE_TILE), - LIST("list", MODE_LIST); - - private final String type; - private final Icon texture; - - DisplayType(String type, UITexture texture) { - this.type = type; - this.texture = texture.asIcon(); - } - - public String getLocalizedName() { - return IKey.lang("vendingmachine.gui.display_mode_" + this.type) - .toString(); - } - - public Icon getTexture() { - return this.texture; - } - } - private MTEVendingMachine vm; private TradeMainPanel rootPanel; private boolean pressed = false; From 48ac09b544e494ccc19ed834c942098f45461dbf Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 13 Dec 2025 12:21:08 +0800 Subject: [PATCH 112/160] Extract sort mode to separate class --- .../com/cubefury/vendingmachine/VMConfig.java | 4 +-- .../blocks/gui/DisplayType.java | 6 ++-- .../blocks/gui/MTEVendingMachineGui.java | 28 ----------------- .../vendingmachine/blocks/gui/SortMode.java | 31 +++++++++++++++++++ .../blocks/gui/TradeMainPanel.java | 6 ++-- 5 files changed, 39 insertions(+), 36 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/blocks/gui/SortMode.java diff --git a/src/main/java/com/cubefury/vendingmachine/VMConfig.java b/src/main/java/com/cubefury/vendingmachine/VMConfig.java index cbd701a..b42703d 100644 --- a/src/main/java/com/cubefury/vendingmachine/VMConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/VMConfig.java @@ -2,8 +2,8 @@ import java.io.File; -import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; import com.cubefury.vendingmachine.blocks.gui.DisplayType; +import com.cubefury.vendingmachine.blocks.gui.SortMode; import com.gtnewhorizon.gtnhlib.config.Config; @Config(modid = VendingMachine.MODID, category = "vendingmachine", filename = "vendingmachine") @@ -44,7 +44,7 @@ public static class GUI { @Config.Comment("Default sort mode, either SMART or ALPHABET. Case sensitive.") @Config.DefaultEnum("SMART") - public MTEVendingMachineGui.SortMode sort_mode = MTEVendingMachineGui.SortMode.SMART; + public SortMode sort_mode = SortMode.SMART; } public static class Developer { diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java index d6704fd..8a4efbe 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/DisplayType.java @@ -1,12 +1,12 @@ package com.cubefury.vendingmachine.blocks.gui; +import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_LIST; +import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_TILE; + import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.drawable.Icon; import com.cleanroommc.modularui.drawable.UITexture; -import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_LIST; -import static com.cubefury.vendingmachine.gui.GuiTextures.MODE_TILE; - public enum DisplayType { TILE("tile", MODE_TILE), 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 6c5cbb4..d0b902d 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -1,8 +1,5 @@ package com.cubefury.vendingmachine.blocks.gui; -import static com.cubefury.vendingmachine.gui.GuiTextures.SORT_ALPHABET; -import static com.cubefury.vendingmachine.gui.GuiTextures.SORT_SMART; - import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -18,8 +15,6 @@ import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; import com.cleanroommc.modularui.drawable.DynamicDrawable; -import com.cleanroommc.modularui.drawable.Icon; -import com.cleanroommc.modularui.drawable.UITexture; import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.RichTooltip; @@ -96,29 +91,6 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { private static final int COIN_COLUMN_WIDTH = 40; private static final int COIN_COLUMN_ROW_COUNT = 4; - public enum SortMode { - - SMART("smart", SORT_SMART), - ALPHABET("alphabet", SORT_ALPHABET); - - private String mode; - private Icon texture; - - SortMode(String mode, UITexture texture) { - this.mode = mode; - this.texture = texture.asIcon(); - } - - public String getLocalizedName() { - return IKey.lang("vendingmachine.gui.display_sort_" + this.mode) - .toString(); - } - - public Icon getTexture() { - return this.texture; - } - } - public MTEVendingMachineGui(MTEVendingMachine base) { super(base); this.base = base; diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/SortMode.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SortMode.java new file mode 100644 index 0000000..93d425e --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SortMode.java @@ -0,0 +1,31 @@ +package com.cubefury.vendingmachine.blocks.gui; + +import static com.cubefury.vendingmachine.gui.GuiTextures.SORT_ALPHABET; +import static com.cubefury.vendingmachine.gui.GuiTextures.SORT_SMART; + +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.drawable.Icon; +import com.cleanroommc.modularui.drawable.UITexture; + +public enum SortMode { + + SMART("smart", SORT_SMART), + ALPHABET("alphabet", SORT_ALPHABET); + + private String mode; + private Icon texture; + + SortMode(String mode, UITexture texture) { + this.mode = mode; + this.texture = texture.asIcon(); + } + + public String getLocalizedName() { + return IKey.lang("vendingmachine.gui.display_sort_" + this.mode) + .toString(); + } + + public Icon getTexture() { + return this.texture; + } +} 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 8d787cc..7d9d9e8 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -127,7 +127,7 @@ public ItemStack convertToItemStack(BigItemStack stack) { public Map> formatTrades() { Map> trades = new HashMap<>(); trades.put(TradeCategory.ALL, new ArrayList<>()); - MTEVendingMachineGui.SortMode sortMode = VMConfig.gui.sort_mode; + SortMode sortMode = VMConfig.gui.sort_mode; for (TradeItemDisplay tid : TradeManager.INSTANCE.tradeData) { TradeGroup group = TradeDatabase.INSTANCE.getTradeGroupFromId(tid.tgID); @@ -159,10 +159,10 @@ public Map> formatTrades() { if (a.display.getItem() == null) return 1; if (b.display.getItem() == null) return -1; - if (sortMode == MTEVendingMachineGui.SortMode.ALPHABET) { + if (sortMode == SortMode.ALPHABET) { return (a.display.getDisplayName() .compareTo(b.display.getDisplayName())); - } else if (sortMode == MTEVendingMachineGui.SortMode.SMART) { + } else if (sortMode == SortMode.SMART) { // enabled or has cooldown int rankA = getRank(a); int rankB = getRank(b); From 49e98cc163864f28dcfac83946be0d3b0f7b1fcd Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 15 Dec 2025 16:34:33 +0800 Subject: [PATCH 113/160] Add Oredict compat --- .../blocks/MTEVendingMachine.java | 55 ++++++++++++++-- .../blocks/MTEVendingUplinkHatch.java | 65 +++++++++++-------- 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 0e06c63..21b3253 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -18,6 +18,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.stream.IntStream; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; @@ -29,6 +30,7 @@ import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.oredict.OreDictionary; import org.jetbrains.annotations.NotNull; import org.lwjgl.input.Keyboard; @@ -289,7 +291,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { requiredStack.setTagCompound(null); 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 + // Remove items from last stacks if possible (exact matches) for (int i = MTEVendingMachine.INPUT_SLOTS - 1; i >= 0 && requiredAmount > 0; i--) { if (inputSlots[i] == null) { continue; @@ -306,8 +308,36 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } } } + // Remove items from last stacks if possible (oredict matches) + if (stack.hasOreDict()) { + String ore = stack.getOreDict(); + for (int i = MTEVendingMachine.INPUT_SLOTS - 1; i >= 0 && requiredAmount > 0; i--) { + if (inputSlots[i] == null) { + continue; + } + ItemStack tmp = inputSlots[i].copy(); + tmp.stackSize = 1; + if ( + IntStream.of(OreDictionary.getOreIDs(tmp)) + .mapToObj(OreDictionary::getOreName) + .anyMatch(s -> s.equals(ore)) + ) { + if (requiredAmount >= inputSlots[i].stackSize) { + requiredAmount -= inputSlots[i].stackSize; + inputSlots[i] = null; + } else { + inputSlots[i].stackSize -= requiredAmount; + requiredAmount = 0; + } + } + } + } + requiredStack.stackSize = requiredAmount; - if (requiredAmount > 0 && !fetchItemFromAE(requiredStack, false)) { + if ( + requiredAmount > 0 + && !fetchItemFromAE(requiredStack, false, stack.hasOreDict() ? stack.getOreDict() : null) + ) { return false; } } @@ -337,9 +367,9 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { return true; } - public boolean fetchItemFromAE(ItemStack requiredStack, boolean simulate) { + public boolean fetchItemFromAE(ItemStack requiredStack, boolean simulate, String ore) { for (MTEVendingUplinkHatch hatch : this.uplinkHatches) { - if (hatch.removeItem(requiredStack, simulate)) { + if (hatch.removeItem(requiredStack, simulate, ore)) { return true; } } @@ -590,6 +620,7 @@ public void refreshInputSlotCache() { public boolean inputItemsSatisfied(List fromItems) { for (BigItemStack bis : fromItems) { BigItemStack base = bis.copy(); + boolean hasOreDict = bis.hasOreDict(); bis.setTagCompound(null); base.stackSize = 1; // shouldn't need this, but just in case @@ -598,11 +629,25 @@ public boolean inputItemsSatisfied(List fromItems) { if (this.inputSlotCache.get(base) != null) { aeStackSearch.stackSize = Math .max(aeStackSearch.stackSize - this.inputSlotCache.getOrDefault(base, 0), 0); + } else if (hasOreDict) { + String ore = bis.getOreDict(); + for (Map.Entry item : this.inputSlotCache.entrySet()) { + if ( + IntStream.of( + OreDictionary.getOreIDs( + item.getKey() + .getBaseStack())) + .mapToObj(OreDictionary::getOreName) + .anyMatch(s -> s.equals(ore)) + ) { + aeStackSearch.stackSize = Math.max(aeStackSearch.stackSize - item.getValue(), 0); + } + } } if (aeStackSearch.stackSize == 0) { continue; } - if (!this.fetchItemFromAE(aeStackSearch, true)) { + if (!this.fetchItemFromAE(aeStackSearch, true, hasOreDict ? bis.getOreDict() : null)) { return false; } } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index c6d23b1..2d7054c 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -3,14 +3,16 @@ import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_ACTIVE; import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_INACTIVE; -import java.util.ArrayList; import java.util.EnumSet; +import java.util.LinkedList; import java.util.List; +import java.util.stream.IntStream; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ChatComponentTranslation; import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.oredict.OreDictionary; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.items.VMItems; @@ -192,13 +194,15 @@ public void refreshStorageContents() { .getStorageList(); } - public boolean removeItem(ItemStack remove, boolean simulate) { + public boolean removeItem(ItemStack remove, boolean simulate, String ore) { if (remove == null || remove.stackSize <= 0) return true; IStorageGrid storage = accessStorage(); if (storage == null) return false; MachineSource source = new MachineSource(this); - if (!remove.isItemStackDamageable()) { + + // shortcut for exact item matches to save compute for majority of trades + if (!remove.isItemStackDamageable() && ore == null) { IAEItemStack stack = storage.getItemInventory() .extractItems(AEItemStack.create(remove), simulate ? Actionable.SIMULATE : Actionable.MODULATE, source); return stack != null && stack.getStackSize() >= remove.stackSize; @@ -208,41 +212,46 @@ public boolean removeItem(ItemStack remove, boolean simulate) { return false; } - List outputList = new ArrayList<>(); + List modulateList = new LinkedList<>(); + + long remain = remove.stackSize; for (IAEItemStack stack : cachedItems) { - if (stack.getItem() == remove.getItem() && stack.getItemDamage() == remove.getItemDamage()) { - outputList.add(stack); + if ( + ore == null && stack.getItem() != remove.getItem() + || ore != null && IntStream.of(OreDictionary.getOreIDs(stack.getItemStack())) + .mapToObj(OreDictionary::getOreName) + .noneMatch(s -> s.equals(ore)) + ) { + continue; } - } - long numMatch = outputList.stream() - .mapToLong(stack -> stack.getStackSize()) - .sum(); - if (simulate || numMatch < remove.stackSize) { - return numMatch >= remove.stackSize; - } + if (stack.getItemDamage() != remove.getItemDamage()) { + continue; + } - // Simulate removing the needed count first, and add successful to modulateList for actual removal, - // due to possible view-only items that can't be actually extracted - long remain = remove.stackSize; - List modulateList = new ArrayList<>(); - for (IAEItemStack removable : outputList) { - long toRemove = Math.min(removable.getStackSize(), remain); - removable.setStackSize(toRemove); - IAEItemStack stack = storage.getItemInventory() - .extractItems(removable, Actionable.SIMULATE, source); - if (stack != null && stack.getItemDamage() == remove.getItemDamage()) { - modulateList.add(stack); - } else { + IAEItemStack copy = stack.copy(); + copy.setStackSize(Math.min(stack.getStackSize(), remain)); + if ( + storage.getItemInventory() + .extractItems(copy, Actionable.SIMULATE, source) == null + ) { continue; } - remain -= toRemove; + remain -= copy.getStackSize(); + + if (stack.getItem() == remove.getItem()) { + modulateList.add(0, copy); + } else { + modulateList.add(stack); + } + if (remain <= 0) { break; } } - if (remain > 0) { - return false; + + if (simulate || remain > 0) { + return remain <= 0; } for (IAEItemStack modulate : modulateList) { From d5250042b9da8345cb8934ae37c83e3bb6834d7d Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 15 Dec 2025 17:36:06 +0800 Subject: [PATCH 114/160] Fix bug where items accepting oredict would accept any item durability --- .../blocks/MTEVendingMachine.java | 32 ++++++++++++------- .../blocks/MTEVendingUplinkHatch.java | 4 +-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 21b3253..b2e12a8 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -286,19 +286,14 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } for (BigItemStack stack : trade.fromItems) { - ItemStack requiredStack = stack.getBaseStack() - .copy(); - requiredStack.setTagCompound(null); - requiredStack.stackSize = 1; // just in case it's not pulled as 1 for some reason + ItemStack requiredStack = stack.getBaseStack(); int requiredAmount = stack.stackSize; // Remove items from last stacks if possible (exact matches) for (int i = MTEVendingMachine.INPUT_SLOTS - 1; i >= 0 && requiredAmount > 0; i--) { if (inputSlots[i] == null) { continue; } - ItemStack tmp = inputSlots[i].copy(); - tmp.stackSize = 1; - if (ItemStack.areItemStacksEqual(requiredStack, tmp)) { + if (requiredStack.isItemEqual(inputSlots[i])) { if (requiredAmount >= inputSlots[i].stackSize) { requiredAmount -= inputSlots[i].stackSize; inputSlots[i] = null; @@ -309,19 +304,23 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } } // Remove items from last stacks if possible (oredict matches) - if (stack.hasOreDict()) { + if (requiredAmount > 0 && stack.hasOreDict()) { String ore = stack.getOreDict(); for (int i = MTEVendingMachine.INPUT_SLOTS - 1; i >= 0 && requiredAmount > 0; i--) { if (inputSlots[i] == null) { continue; } - ItemStack tmp = inputSlots[i].copy(); - tmp.stackSize = 1; if ( - IntStream.of(OreDictionary.getOreIDs(tmp)) + IntStream.of(OreDictionary.getOreIDs(inputSlots[i])) .mapToObj(OreDictionary::getOreName) .anyMatch(s -> s.equals(ore)) ) { + if ( + requiredStack.isItemStackDamageable() + && requiredStack.getItemDamage() != inputSlots[i].getItemDamage() + ) { + continue; + } if (requiredAmount >= inputSlots[i].stackSize) { requiredAmount -= inputSlots[i].stackSize; inputSlots[i] = null; @@ -629,7 +628,9 @@ public boolean inputItemsSatisfied(List fromItems) { if (this.inputSlotCache.get(base) != null) { aeStackSearch.stackSize = Math .max(aeStackSearch.stackSize - this.inputSlotCache.getOrDefault(base, 0), 0); - } else if (hasOreDict) { + } + + if (aeStackSearch.stackSize > 0 && hasOreDict) { String ore = bis.getOreDict(); for (Map.Entry item : this.inputSlotCache.entrySet()) { if ( @@ -640,6 +641,13 @@ public boolean inputItemsSatisfied(List fromItems) { .mapToObj(OreDictionary::getOreName) .anyMatch(s -> s.equals(ore)) ) { + if ( + aeStackSearch.isItemStackDamageable() && aeStackSearch.getItemDamage() != item.getKey() + .getBaseStack() + .getItemDamage() + ) { + continue; + } aeStackSearch.stackSize = Math.max(aeStackSearch.stackSize - item.getValue(), 0); } } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java index 2d7054c..66fe473 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -225,7 +225,7 @@ public boolean removeItem(ItemStack remove, boolean simulate, String ore) { continue; } - if (stack.getItemDamage() != remove.getItemDamage()) { + if (remove.isItemStackDamageable() && stack.getItemDamage() != remove.getItemDamage()) { continue; } @@ -242,7 +242,7 @@ public boolean removeItem(ItemStack remove, boolean simulate, String ore) { if (stack.getItem() == remove.getItem()) { modulateList.add(0, copy); } else { - modulateList.add(stack); + modulateList.add(copy); } if (remain <= 0) { From 51bc41894019510fcdd247abd7f6cfce3770db8f Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 17 Dec 2025 02:53:28 +0800 Subject: [PATCH 115/160] Address comments --- .../com/cubefury/vendingmachine/blocks/MTEVendingMachine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index b2e12a8..a4b8e3a 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -620,7 +620,7 @@ public boolean inputItemsSatisfied(List fromItems) { for (BigItemStack bis : fromItems) { BigItemStack base = bis.copy(); boolean hasOreDict = bis.hasOreDict(); - bis.setTagCompound(null); + base.setTagCompound(null); base.stackSize = 1; // shouldn't need this, but just in case ItemStack aeStackSearch = base.getBaseStack(); From 982fd0c8a61004c98090c9f35466dd54265883db Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 18 Dec 2025 01:09:09 +0800 Subject: [PATCH 116/160] Add Oredict tooltips --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 8 +++++++- src/main/resources/assets/vendingmachine/lang/en_US.lang | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) 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 d0b902d..2e17e92 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -451,7 +451,13 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { IKey.str( fromItem.stackSize + " " + fromItem.getBaseStack() - .getDisplayName()) + .getDisplayName() + + (fromItem.hasOreDict() + ? " (" + IKey.lang("vendingmachine.gui.alternative_oredict") + + " " + + fromItem.getOreDict() + + ")" + : "")) .style(IKey.DARK_GREEN)); } builder.emptyLine(); diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index d78d3bc..a160f03 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -17,6 +17,7 @@ vendingmachine.gui.single_coin_type_eject_hint=Shift-Click to Extract vendingmachine.gui.search=Search vendingmachine.gui.required_inputs=Requires: vendingmachine.gui.nc_inputs=Requires (Not Consumed): +vendingmachine.gui.alternative_oredict=Accepts Oredict: vendingmachine.gui.nc_inputs_overlay_color=FDD835 vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.display_mode=Display: From 2e803791a20a080ed85473ed20566b2383152eb0 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 19 Dec 2025 01:16:28 +0800 Subject: [PATCH 117/160] Added more slots --- .../blocks/MTEVendingMachine.java | 48 +++++++++++++++++-- .../blocks/gui/MTEVendingMachineGui.java | 14 +++--- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index a4b8e3a..3291402 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -97,8 +97,8 @@ public class MTEVendingMachine extends MTEMultiBlockBase private final ArrayList uplinkHatches = new ArrayList<>(); - public static final int INPUT_SLOTS = 6; - public static final int OUTPUT_SLOTS = 6; + public static final int INPUT_SLOTS = 8; + public static final int OUTPUT_SLOTS = 8; public static final int MAX_TRADES = 300; @@ -500,15 +500,53 @@ public void saveNBTData(NBTTagCompound aNBT) { @Override public void loadNBTData(NBTTagCompound aNBT) { super.loadNBTData(aNBT); + boolean loadedLegacyData = false; + + NBTTagList pendingOutputs = aNBT.getTagList("outputBuffer", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < pendingOutputs.tagCount(); i++) { + outputBuffer.add(GTUtility.loadItem(pendingOutputs.getCompoundTagAt(i))); + } + if (inputItems != null) { inputItems.deserializeNBT(aNBT.getCompoundTag("inputs")); + if (inputItems.getSlots() != MTEVendingMachine.INPUT_SLOTS) { + loadedLegacyData = true; + List oldStacks = new ArrayList<>(); + for (int i = 0; i < inputItems.getSlots(); i++) { + oldStacks.add(inputItems.getStackInSlot(i)); + } + inputItems.setSize(MTEVendingMachine.INPUT_SLOTS); + for (int i = 0; i < oldStacks.size(); i++) { + if (i >= MTEVendingMachine.INPUT_SLOTS) { + outputBuffer.add(oldStacks.get(i)); + } else { + inputItems.setStackInSlot(i, oldStacks.get(i)); + } + } + } } + if (outputItems != null) { outputItems.deserializeNBT(aNBT.getCompoundTag("outputs")); + if (outputItems.getSlots() != MTEVendingMachine.OUTPUT_SLOTS) { + loadedLegacyData = true; + List oldStacks = new ArrayList<>(); + for (int i = 0; i < outputItems.getSlots(); i++) { + oldStacks.add(outputItems.getStackInSlot(i)); + } + outputItems.setSize(MTEVendingMachine.OUTPUT_SLOTS); + for (int i = 0; i < oldStacks.size(); i++) { + if (i >= MTEVendingMachine.OUTPUT_SLOTS) { + outputBuffer.add(oldStacks.get(i)); + } else { + outputItems.setStackInSlot(i, oldStacks.get(i)); + } + } + } } - NBTTagList pendingOutputs = aNBT.getTagList("outputBuffer", Constants.NBT.TAG_COMPOUND); - for (int i = 0; i < pendingOutputs.tagCount(); i++) { - outputBuffer.add(GTUtility.loadItem(pendingOutputs.getCompoundTagAt(i))); + + if (loadedLegacyData) { + this.markDirty(); } } 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 2e17e92..c568217 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -335,7 +335,7 @@ private void doEjectItems() { private IWidget createIOColumn() { return new ParentWidget<>().excludeAreaInRecipeViewer() .width(50) - .height(178) + .height(214) .right(-48) .top(40) .widgetTheme(WidgetThemes.BACKGROUND_SIDEPANEL) @@ -349,7 +349,7 @@ private IWidget createIOColumn() { .child( new Row().child(createInputSlots().center()) .top(20) - .height(18 * 3)) + .height(18 * 4)) .child( new Row().child( new ToggleButton().overlay(GTGuiTextures.OVERLAY_BUTTON_CYCLIC) @@ -363,24 +363,24 @@ private IWidget createIOColumn() { .tooltipBuilder(t -> t.addLine(IKey.lang("vendingmachine.gui.coin_eject"))) .syncHandler("ejectCoins") .left(6)) - .top(80) + .top(98) .height(18)) .child( GuiTextures.OUTPUT_SPRITE.asWidget() .leftRel(0.5f) - .bottom(52) + .bottom(70) .width(30) .height(20)) .child( new Row().child(createOutputSlots().center()) .bottom(6) - .height(18 * 3)) + .height(18 * 4)) .right(1)); } private SlotGroupWidget createInputSlots() { return SlotGroupWidget.builder() - .matrix("II", "II", "II") + .matrix("II", "II", "II", "II") .key('I', index -> { InterceptingSlot slot = new InterceptingSlot(base.inputItems, index, this.base); this.inputSlots.add(slot); @@ -414,7 +414,7 @@ private SlotGroupWidget createInputSlots() { private SlotGroupWidget createOutputSlots() { return SlotGroupWidget.builder() - .matrix("II", "II", "II") + .matrix("II", "II", "II", "II") .key('I', index -> { return new ItemSlot().slot( new ModularSlot(base.outputItems, index).accessibility(false, true) From 988a8ef37ed74cdd85bb6ac9571b149576c3085d Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 19 Dec 2025 02:19:58 +0800 Subject: [PATCH 118/160] swap to getStacks --- .../vendingmachine/blocks/MTEVendingMachine.java | 10 ++-------- 1 file 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 3291402..9cc51b8 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -511,10 +511,7 @@ public void loadNBTData(NBTTagCompound aNBT) { inputItems.deserializeNBT(aNBT.getCompoundTag("inputs")); if (inputItems.getSlots() != MTEVendingMachine.INPUT_SLOTS) { loadedLegacyData = true; - List oldStacks = new ArrayList<>(); - for (int i = 0; i < inputItems.getSlots(); i++) { - oldStacks.add(inputItems.getStackInSlot(i)); - } + List oldStacks = inputItems.getStacks(); inputItems.setSize(MTEVendingMachine.INPUT_SLOTS); for (int i = 0; i < oldStacks.size(); i++) { if (i >= MTEVendingMachine.INPUT_SLOTS) { @@ -530,10 +527,7 @@ public void loadNBTData(NBTTagCompound aNBT) { outputItems.deserializeNBT(aNBT.getCompoundTag("outputs")); if (outputItems.getSlots() != MTEVendingMachine.OUTPUT_SLOTS) { loadedLegacyData = true; - List oldStacks = new ArrayList<>(); - for (int i = 0; i < outputItems.getSlots(); i++) { - oldStacks.add(outputItems.getStackInSlot(i)); - } + List oldStacks = outputItems.getStacks(); outputItems.setSize(MTEVendingMachine.OUTPUT_SLOTS); for (int i = 0; i < oldStacks.size(); i++) { if (i >= MTEVendingMachine.OUTPUT_SLOTS) { From a5c0206f2ee06b73448ac7bc077fea1e6142bfbe Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 19 Dec 2025 14:25:29 +0800 Subject: [PATCH 119/160] Removed clientside code from serverside oredict check --- .../java/com/cubefury/vendingmachine/util/BigItemStack.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java b/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java index f0e23ea..a84d2a6 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java +++ b/src/main/java/com/cubefury/vendingmachine/util/BigItemStack.java @@ -72,7 +72,7 @@ public ItemStack getBaseStack() { @SuppressWarnings("BooleanMethodIsAlwaysInverted") public boolean hasOreDict() { - return !StringUtils.isNullOrEmpty(this.oreDict) && this.oreIng.getMatchingStacks().length > 0; + return !StringUtils.isNullOrEmpty(this.oreDict); } @Nonnull From 43195b39396e074d3328f4b0b34707d81c4731c6 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 20 Dec 2025 17:29:35 +0800 Subject: [PATCH 120/160] Add periodic check for trade restock notifications. --- .../com/cubefury/vendingmachine/VMConfig.java | 10 ++++++++++ .../vendingmachine/handlers/EventHandler.java | 17 +++++++++++++++++ .../vendingmachine/trade/TradeDatabase.java | 11 +++++++++++ .../assets/vendingmachine/lang/en_US.lang | 1 + 4 files changed, 39 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/VMConfig.java b/src/main/java/com/cubefury/vendingmachine/VMConfig.java index b42703d..cff49b0 100644 --- a/src/main/java/com/cubefury/vendingmachine/VMConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/VMConfig.java @@ -25,6 +25,16 @@ public static class VendingMachineSettings { @Config.RequiresWorldRestart public int gui_refresh_interval; + @Config.Comment("Enable restock notifications") + @Config.DefaultBoolean(true) + @Config.RequiresWorldRestart + public boolean restock_notifications_enabled; + + @Config.Comment("How often the server checks for restocked trades, in number of ticks") + @Config.DefaultInt(200) + @Config.RequiresWorldRestart + public int restock_notifications_interval; + @Config.Comment("How often items items are ejected, in number of ticks") @Config.DefaultInt(10) @Config.RequiresWorldRestart diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index 0420450..9f7e89c 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -18,6 +18,7 @@ import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularContainer; +import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.events.MarkDirtyDbEvent; @@ -25,6 +26,7 @@ import com.cubefury.vendingmachine.network.handlers.NetBulkSync; import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.TradeDatabase; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFutureTask; @@ -140,6 +142,21 @@ public void onServerTick(TickEvent.ServerTickEvent event) { NameCache.INSTANCE.updateName(playerMP); } } + + for (EntityPlayerMP player : server.getConfigurationManager().playerEntityList) { + livingPlayerTick(player); + } + } + + private void livingPlayerTick(@Nonnull EntityPlayerMP player) { + if ( + !VMConfig.vendingMachineSettings.restock_notifications_enabled + || player.ticksExisted % VMConfig.vendingMachineSettings.restock_notifications_interval != 0 + ) { + return; + } + + TradeDatabase.INSTANCE.sendTradeNotifications(player); } private void terminateVendingSession(@Nonnull EntityPlayer player) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 74b0e1e..43080c3 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -11,8 +11,11 @@ import javax.annotation.Nonnull; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.common.util.Constants; import com.cubefury.vendingmachine.VMConfig; @@ -156,6 +159,14 @@ public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, @Nonnull UUID pla return nbt; } + public void sendTradeNotifications(EntityPlayerMP player) { + String refreshedTrades = "a"; + player.addChatComponentMessage( + new ChatComponentTranslation( + "vendingmachine.chat.trade_restock", + EnumChatFormatting.YELLOW + refreshedTrades)); + } + @SideOnly(Side.CLIENT) public void refreshNeiCache() { NeiRecipeCache.refreshCache(); diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index a160f03..78d5675 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -33,6 +33,7 @@ vendingmachine.gui.cooldown_display.hour=h vendingmachine.gui.cooldown_display.day=d vendingmachine.gui.error.player_using=Someone is using the vending machine at the moment. +vendingmachine.chat.trade_restock=Vending Machine Restocked: %s gt.blockmachines.multimachine.vendingmachine.name=Vending Machine gt.blockmachines.multimachine.vendingmachine.name.gui=Vending Machine From e35920023d445455fcb68d12157b323bb8c41649 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Sat, 20 Dec 2025 11:55:36 +0100 Subject: [PATCH 121/160] update --- dependencies.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 2661237..6bfec3d 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.26-GTNH:dev") - implementation("com.github.GTNewHorizons:GTNHLib:0.8.13:dev") - compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.10-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.43-GTNH:dev") + implementation("com.github.GTNewHorizons:GTNHLib:0.8.34:dev") + compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.14-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.5-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.24-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.24:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.95:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.154:dev") } // deps may transitively add Baubles, so we replace it @@ -49,7 +49,7 @@ project.getConfigurations() final DependencySubstitutions ds = c.getResolutionStrategy() .getDependencySubstitution() ds.substitute(ds.module("com.github.GTNewHorizons:Baubles")) - .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.2.2-GTNH")) + .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.2.4-GTNH")) .withClassifier("dev") .because("Baubles-Expanded replaces Baubles") }) From 273bb6c9e9b327549f326031ea5328d0c88ccd92 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 22 Dec 2025 18:38:40 +0800 Subject: [PATCH 122/160] Added notification send and set/reset --- .../com/cubefury/vendingmachine/VMConfig.java | 4 +- .../vendingmachine/handlers/EventHandler.java | 4 +- .../handlers/NotificationHandler.java | 27 +++++++++ .../network/PacketTypeRegistry.java | 2 + .../handlers/NetTradeNotification.java | 57 +++++++++++++++++++ .../vendingmachine/trade/TradeDatabase.java | 25 ++++---- .../vendingmachine/trade/TradeGroup.java | 12 ++++ .../vendingmachine/trade/TradeHistory.java | 13 ++++- .../vendingmachine/trade/TradeManager.java | 47 +++++++++++++++ 9 files changed, 173 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java create mode 100644 src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java diff --git a/src/main/java/com/cubefury/vendingmachine/VMConfig.java b/src/main/java/com/cubefury/vendingmachine/VMConfig.java index cff49b0..134ab8c 100644 --- a/src/main/java/com/cubefury/vendingmachine/VMConfig.java +++ b/src/main/java/com/cubefury/vendingmachine/VMConfig.java @@ -25,12 +25,12 @@ public static class VendingMachineSettings { @Config.RequiresWorldRestart public int gui_refresh_interval; - @Config.Comment("Enable restock notifications") + @Config.Comment("Enable restock notifications, disabling on server will disable notifications for everyone") @Config.DefaultBoolean(true) @Config.RequiresWorldRestart public boolean restock_notifications_enabled; - @Config.Comment("How often the server checks for restocked trades, in number of ticks") + @Config.Comment("How often the server checks for restocked trades, in number of ticks.") @Config.DefaultInt(200) @Config.RequiresWorldRestart public int restock_notifications_interval; diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index 9f7e89c..8b68dea 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -26,7 +26,7 @@ import com.cubefury.vendingmachine.network.handlers.NetBulkSync; import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; import com.cubefury.vendingmachine.storage.NameCache; -import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeManager; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFutureTask; @@ -156,7 +156,7 @@ private void livingPlayerTick(@Nonnull EntityPlayerMP player) { return; } - TradeDatabase.INSTANCE.sendTradeNotifications(player); + TradeManager.INSTANCE.sendTradeNotifications(player); } private void terminateVendingSession(@Nonnull EntityPlayer player) { diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java new file mode 100644 index 0000000..9e5cd5c --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java @@ -0,0 +1,27 @@ +package com.cubefury.vendingmachine.handlers; + +import java.util.List; +import java.util.UUID; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class NotificationHandler { + + public static NotificationHandler INSTANCE = new NotificationHandler(); + + private NotificationHandler() {} + + public void displayNotification(List tradeGroups) { + String refreshedTrades = "a"; + Minecraft.getMinecraft().thePlayer.addChatComponentMessage( + new ChatComponentTranslation( + "vendingmachine.chat.trade_restock", + EnumChatFormatting.YELLOW + refreshedTrades)); + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java b/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java index 6540eef..99cf435 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java +++ b/src/main/java/com/cubefury/vendingmachine/network/PacketTypeRegistry.java @@ -18,6 +18,7 @@ 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.NetTradeNotification; import com.cubefury.vendingmachine.network.handlers.NetTradeRequestSync; public class PacketTypeRegistry implements IPacketRegistry { @@ -35,6 +36,7 @@ public void init() { NetNameSync.registerHandler(); NetBulkSync.registerHandler(); NetResetVMUser.registerHandler(); + NetTradeNotification.registerHandler(); } @Override diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java new file mode 100644 index 0000000..9b2bf24 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java @@ -0,0 +1,57 @@ +package com.cubefury.vendingmachine.network.handlers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import javax.annotation.Nonnull; + +import net.minecraft.entity.player.EntityPlayerMP; +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.handlers.NotificationHandler; +import com.cubefury.vendingmachine.network.PacketSender; +import com.cubefury.vendingmachine.network.PacketTypeRegistry; +import com.cubefury.vendingmachine.util.NBTConverter; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class NetTradeNotification { + + private static final ResourceLocation ID_NAME = new ResourceLocation("vendingmachine:trade_notification"); + + public static void registerHandler() { + if (VendingMachine.proxy.isClient()) { + PacketTypeRegistry.INSTANCE.registerClientHandler(ID_NAME, NetTradeNotification::onClient); + } + } + + public static void sendNotification(@Nonnull EntityPlayerMP player, Set tradeGroups) { + NBTTagCompound payload = new NBTTagCompound(); + NBTTagList notifications = new NBTTagList(); + for (UUID tgId : tradeGroups) { + notifications.appendTag(NBTConverter.UuidValueType.TRADEGROUP.writeId(tgId)); + } + payload.setTag("notifications", notifications); + PacketSender.INSTANCE.sendToPlayers(new UnserializedPacket(ID_NAME, payload), player); + } + + @SideOnly(Side.CLIENT) + public static void onClient(NBTTagCompound message) { + List tradeNotifications = new ArrayList<>(); + + NBTTagList notifNbt = message.getTagList("notifications", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < notifNbt.tagCount(); i++) { + tradeNotifications.add(NBTConverter.UuidValueType.TRADEGROUP.readId(notifNbt.getCompoundTagAt(i))); + } + + NotificationHandler.INSTANCE.displayNotification(tradeNotifications); + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 43080c3..f66ee72 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -11,11 +11,8 @@ import javax.annotation.Nonnull; -import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; -import net.minecraft.util.ChatComponentTranslation; -import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.common.util.Constants; import com.cubefury.vendingmachine.VMConfig; @@ -45,6 +42,7 @@ public void clear() { public void clearTradeState(UUID player) { tradeGroups.forEach((k, v) -> v.clearTradeState(player)); TradeManager.INSTANCE.clearCurrency(player); + TradeManager.INSTANCE.clearNotificationQueue(player); } public TradeGroup getTradeGroupFromId(UUID tgId) { @@ -133,9 +131,19 @@ public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean m NBTTagCompound state = tradeStateList.getCompoundTagAt(i); UUID tgId = NBTConverter.UuidValueType.TRADEGROUP.readId(state); TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); - TradeHistory th = new TradeHistory(state.getLong("lastTrade"), state.getInteger("tradeCount")); + boolean notificationQueued = false; + if (state.hasKey("notificationQueued")) { + notificationQueued = state.getBoolean("notificationQueued"); + } + TradeHistory th = new TradeHistory( + state.getLong("lastTrade"), + state.getInteger("tradeCount"), + notificationQueued); if (tg != null) { tg.setTradeState(player, th); + if (notificationQueued) { + TradeManager.INSTANCE.addNotification(player, tg); + } } } TradeManager.INSTANCE.populateCurrencyFromNBT(nbt, player, merge); @@ -151,6 +159,7 @@ public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, @Nonnull UUID pla NBTConverter.UuidValueType.TRADEGROUP.writeId(entry.getKey(), state); state.setLong("lastTrade", history.lastTrade); state.setInteger("tradeCount", history.tradeCount); + state.setBoolean("notificationQueued", history.notificationQueued); tradeStateList.appendTag(state); } } @@ -159,14 +168,6 @@ public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, @Nonnull UUID pla return nbt; } - public void sendTradeNotifications(EntityPlayerMP player) { - String refreshedTrades = "a"; - player.addChatComponentMessage( - new ChatComponentTranslation( - "vendingmachine.chat.trade_restock", - EnumChatFormatting.YELLOW + refreshedTrades)); - } - @SideOnly(Side.CLIENT) public void refreshNeiCache() { NeiRecipeCache.refreshCache(); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index f45b017..c13d887 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -9,6 +9,8 @@ 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; @@ -169,6 +171,16 @@ public void executeTrade(UUID player) { newTradeHistory.executeTrade(); setTradeState(player, newTradeHistory); SaveLoadHandler.INSTANCE.writeTradeState(Collections.singleton(player)); + TradeManager.INSTANCE.addNotification(player, this); + } + + public void resetNotification(@Nonnull UUID player) { + synchronized (tradeState) { + TradeHistory history = tradeState.get(player); + if (history != null) { + history.setNotified(); + } + } } public boolean readFromNBT(NBTTagCompound nbt) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java index bdaaf4f..2ba97da 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java @@ -4,28 +4,37 @@ public class TradeHistory { public long lastTrade = -1; public int tradeCount = 0; + public boolean notificationQueued = false; public static TradeHistory DEFAULT = new TradeHistory(); public TradeHistory() {} - public TradeHistory(long lastTrade, int tradeCount) { + public TradeHistory(long lastTrade, int tradeCount, boolean notificationQueued) { this.lastTrade = lastTrade; this.tradeCount = tradeCount; + this.notificationQueued = notificationQueued; } public void executeTrade() { lastTrade = System.currentTimeMillis(); tradeCount += 1; + notificationQueued = true; + } + + public void setNotified() { + notificationQueued = false; } public void resetData() { lastTrade = -1; tradeCount = 0; + notificationQueued = false; } - public void resetTradeAvailability() { + public void resetTradeAvailability(boolean notifyPlayer) { lastTrade = -1; + notificationQueued = notifyPlayer; } @Override diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 058f734..64883cf 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -1,6 +1,7 @@ package com.cubefury.vendingmachine.trade; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -10,12 +11,16 @@ import javax.annotation.Nonnull; +import net.minecraft.entity.player.EntityPlayerMP; 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; +import com.cubefury.vendingmachine.handlers.SaveLoadHandler; +import com.cubefury.vendingmachine.network.handlers.NetTradeNotification; +import com.cubefury.vendingmachine.storage.NameCache; // 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 @@ -27,6 +32,7 @@ public class TradeManager { private final List noConditionTrades = new ArrayList<>(); public final Map> playerCurrency = new HashMap<>(); + public final Map> notificationQueue = new HashMap<>(); // For writeback to file in original format, to prevent data loss private final Map> invalidCurrency = new HashMap<>(); @@ -187,4 +193,45 @@ public void clearCurrency(UUID player) { this.invalidCurrency.remove(player); } } + + public void clearNotificationQueue(UUID playerOrNull) { + Set playerList = playerOrNull == null ? this.notificationQueue.keySet() + : Collections.singleton(playerOrNull); + for (UUID player : playerList) { + Set tradeGroups = this.notificationQueue.get(player); + if (tradeGroups == null) { + continue; + } + for (UUID tgId : tradeGroups) { + TradeGroup tradeGroup = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); + if (tradeGroup == null) { + continue; + } + tradeGroup.resetNotification(player); + } + } + + SaveLoadHandler.INSTANCE.writeTradeState(playerList); + if (playerOrNull == null) { + this.notificationQueue.clear(); + } else { + this.notificationQueue.remove(playerOrNull); + } + } + + public void addNotification(UUID player, TradeGroup tg) { + this.notificationQueue.putIfAbsent(player, new HashSet<>()); + this.notificationQueue.get(player) + .add(tg.getId()); + } + + public void sendTradeNotifications(EntityPlayerMP player) { + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); + Set tradeGroups = this.notificationQueue.get(playerId); + if (tradeGroups == null) { + return; + } + NetTradeNotification.sendNotification(player, tradeGroups); + this.clearNotificationQueue(playerId); + } } From 6a9fca1403b747b84a525c05420ea632b8f431f3 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 22 Dec 2025 19:07:32 +0800 Subject: [PATCH 123/160] Send notifications only when trade is refreshed --- .../vendingmachine/trade/TradeGroup.java | 15 ++----- .../vendingmachine/trade/TradeHistory.java | 4 +- .../vendingmachine/trade/TradeManager.java | 43 +++++++++++-------- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index c13d887..a186613 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -9,8 +9,6 @@ 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; @@ -168,18 +166,11 @@ public boolean canExecuteTrade(UUID player) { public void executeTrade(UUID player) { TradeHistory newTradeHistory = getTradeState(player); - newTradeHistory.executeTrade(); + newTradeHistory.executeTrade(maxTrades, this.cooldown != -1); setTradeState(player, newTradeHistory); SaveLoadHandler.INSTANCE.writeTradeState(Collections.singleton(player)); - TradeManager.INSTANCE.addNotification(player, this); - } - - public void resetNotification(@Nonnull UUID player) { - synchronized (tradeState) { - TradeHistory history = tradeState.get(player); - if (history != null) { - history.setNotified(); - } + if (newTradeHistory.notificationQueued) { + TradeManager.INSTANCE.addNotification(player, this); } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java index 2ba97da..52a1a27 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java @@ -16,10 +16,10 @@ public TradeHistory(long lastTrade, int tradeCount, boolean notificationQueued) this.notificationQueued = notificationQueued; } - public void executeTrade() { + public void executeTrade(int maxTrades, boolean hasCooldown) { lastTrade = System.currentTimeMillis(); tradeCount += 1; - notificationQueued = true; + notificationQueued = hasCooldown && maxTrades > -1 && tradeCount < maxTrades; } public void setNotified() { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 64883cf..a8c09f2 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -195,23 +195,6 @@ public void clearCurrency(UUID player) { } public void clearNotificationQueue(UUID playerOrNull) { - Set playerList = playerOrNull == null ? this.notificationQueue.keySet() - : Collections.singleton(playerOrNull); - for (UUID player : playerList) { - Set tradeGroups = this.notificationQueue.get(player); - if (tradeGroups == null) { - continue; - } - for (UUID tgId : tradeGroups) { - TradeGroup tradeGroup = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); - if (tradeGroup == null) { - continue; - } - tradeGroup.resetNotification(player); - } - } - - SaveLoadHandler.INSTANCE.writeTradeState(playerList); if (playerOrNull == null) { this.notificationQueue.clear(); } else { @@ -231,7 +214,29 @@ public void sendTradeNotifications(EntityPlayerMP player) { if (tradeGroups == null) { return; } - NetTradeNotification.sendNotification(player, tradeGroups); - this.clearNotificationQueue(playerId); + + long currentTimestamp = System.currentTimeMillis(); + + List notifList = new ArrayList<>(); + for (UUID tgId : tradeGroups) { + TradeGroup tradeGroup = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); + if (tradeGroup == null) { + continue; + } + TradeHistory th = tradeGroup.getTradeState(playerId); + if ((currentTimestamp - th.lastTrade) / 1000 > tradeGroup.cooldown) { + notifList.add(tgId); + th.setNotified(); + } + } + + if (!notifList.isEmpty()) { + NetTradeNotification.sendNotification(player, tradeGroups); + SaveLoadHandler.INSTANCE.writeTradeState(Collections.singleton(playerId)); + } + + for (UUID tg : notifList) { + tradeGroups.remove(tg); + } } } From 779ea3e7b1884caab438a9303fb9dd19ba1de3f5 Mon Sep 17 00:00:00 2001 From: cubefury Date: Mon, 22 Dec 2025 21:39:49 +0800 Subject: [PATCH 124/160] Add sounds, Fix bug where all items with a trade history would show up in the notification --- .../vendingmachine/handlers/EventHandler.java | 2 +- .../handlers/NotificationHandler.java | 60 ++++++++++++++++++- .../handlers/NetTradeNotification.java | 8 ++- .../vendingmachine/trade/TradeHistory.java | 2 +- .../vendingmachine/trade/TradeManager.java | 10 ++-- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index 8b68dea..64e0044 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -150,7 +150,7 @@ public void onServerTick(TickEvent.ServerTickEvent event) { private void livingPlayerTick(@Nonnull EntityPlayerMP player) { if ( - !VMConfig.vendingMachineSettings.restock_notifications_enabled + !VMConfig.vendingMachineSettings.restock_notifications_enabled || player.ticksExisted == 0 || player.ticksExisted % VMConfig.vendingMachineSettings.restock_notifications_interval != 0 ) { return; diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java index 9e5cd5c..299b92d 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java @@ -1,27 +1,81 @@ package com.cubefury.vendingmachine.handlers; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import net.minecraft.client.Minecraft; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.EnumChatFormatting; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularContainer; +import com.cubefury.vendingmachine.blocks.MTEVendingMachine; +import com.cubefury.vendingmachine.trade.Trade; +import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeGroup; +import com.cubefury.vendingmachine.util.BigItemStack; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; @SideOnly(Side.CLIENT) public class NotificationHandler { + private static final int MAX_NOTIFICATION_ITEMS = 4; public static NotificationHandler INSTANCE = new NotificationHandler(); private NotificationHandler() {} public void displayNotification(List tradeGroups) { - String refreshedTrades = "a"; - Minecraft.getMinecraft().thePlayer.addChatComponentMessage( + Minecraft mc = Minecraft.getMinecraft(); + + // If player is already accessing a vending machine, don't send notifications + if ( + mc.thePlayer.openContainer instanceof ModularContainer + && ((ModularContainer) mc.thePlayer.openContainer).getGuiData() instanceof PosGuiData + ) { + TileEntity te = ((PosGuiData) ((ModularContainer) mc.thePlayer.openContainer).getGuiData()).getTileEntity(); + if ( + te instanceof IGregTechTileEntity + && ((IGregTechTileEntity) te).getMetaTileEntity() instanceof MTEVendingMachine + ) { + return; + } + } + + List refreshedTrades = new ArrayList<>(); + for (UUID tgid : tradeGroups) { + TradeGroup tradeGroup = TradeDatabase.INSTANCE.getTradeGroupFromId(tgid); + if (tradeGroup == null) { + continue; + } + for (Trade trade : tradeGroup.getTrades()) { + for (BigItemStack stack : trade.toItems) { + refreshedTrades.add( + stack.getBaseStack() + .getDisplayName()); + } + } + } + + int count = refreshedTrades.size(); + String items_output = ""; + if (count == 0) { + return; + } else if (count > MAX_NOTIFICATION_ITEMS) { + refreshedTrades = refreshedTrades.subList(0, MAX_NOTIFICATION_ITEMS); + items_output += String.join(", ", refreshedTrades) + ", ... [+" + (count - MAX_NOTIFICATION_ITEMS) + "]"; + } else { + items_output += String.join(", ", refreshedTrades); + } + + mc.thePlayer.addChatComponentMessage( new ChatComponentTranslation( "vendingmachine.chat.trade_restock", - EnumChatFormatting.YELLOW + refreshedTrades)); + EnumChatFormatting.YELLOW + items_output)); + mc.thePlayer.playSound("random.orb", 0.2F, 1.8F); } } diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java index 9b2bf24..77cd71b 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeNotification.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Set; import java.util.UUID; import javax.annotation.Nonnull; @@ -13,6 +12,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.util.Constants; +import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.api.network.UnserializedPacket; import com.cubefury.vendingmachine.handlers.NotificationHandler; @@ -33,7 +33,7 @@ public static void registerHandler() { } } - public static void sendNotification(@Nonnull EntityPlayerMP player, Set tradeGroups) { + public static void sendNotification(@Nonnull EntityPlayerMP player, List tradeGroups) { NBTTagCompound payload = new NBTTagCompound(); NBTTagList notifications = new NBTTagList(); for (UUID tgId : tradeGroups) { @@ -45,6 +45,10 @@ public static void sendNotification(@Nonnull EntityPlayerMP player, Set tr @SideOnly(Side.CLIENT) public static void onClient(NBTTagCompound message) { + if (!VMConfig.vendingMachineSettings.restock_notifications_enabled) { + return; + } + List tradeNotifications = new ArrayList<>(); NBTTagList notifNbt = message.getTagList("notifications", Constants.NBT.TAG_COMPOUND); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java index 52a1a27..bb80b77 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeHistory.java @@ -19,7 +19,7 @@ public TradeHistory(long lastTrade, int tradeCount, boolean notificationQueued) public void executeTrade(int maxTrades, boolean hasCooldown) { lastTrade = System.currentTimeMillis(); tradeCount += 1; - notificationQueued = hasCooldown && maxTrades > -1 && tradeCount < maxTrades; + notificationQueued = hasCooldown && (maxTrades == -1 || tradeCount < maxTrades); } public void setNotified() { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index a8c09f2..f6fb7a2 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -210,15 +210,15 @@ public void addNotification(UUID player, TradeGroup tg) { public void sendTradeNotifications(EntityPlayerMP player) { UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(player); - Set tradeGroups = this.notificationQueue.get(playerId); - if (tradeGroups == null) { + Set notifGroups = this.notificationQueue.get(playerId); + if (notifGroups == null) { return; } long currentTimestamp = System.currentTimeMillis(); List notifList = new ArrayList<>(); - for (UUID tgId : tradeGroups) { + for (UUID tgId : notifGroups) { TradeGroup tradeGroup = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); if (tradeGroup == null) { continue; @@ -231,12 +231,12 @@ public void sendTradeNotifications(EntityPlayerMP player) { } if (!notifList.isEmpty()) { - NetTradeNotification.sendNotification(player, tradeGroups); + NetTradeNotification.sendNotification(player, notifList); SaveLoadHandler.INSTANCE.writeTradeState(Collections.singleton(playerId)); } for (UUID tg : notifList) { - tradeGroups.remove(tg); + notifGroups.remove(tg); } } } From fe7e4db34437901f367bbdb8870e82b4447e4db2 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 23 Dec 2025 13:42:22 +0800 Subject: [PATCH 125/160] Address comments --- .../vendingmachine/handlers/EventHandler.java | 19 +++++++------------ .../handlers/NotificationHandler.java | 11 ++++------- .../vendingmachine/trade/TradeDatabase.java | 5 +---- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index 64e0044..d2c3d0e 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -60,11 +60,9 @@ public void onMarkDirtyNames(MarkDirtyNamesEvent event) { public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { if ( event.player.worldObj.isRemote || MinecraftServer.getServer() == null - || !(event.player instanceof EntityPlayerMP) + || !(event.player instanceof EntityPlayerMP mpPlayer) ) return; - EntityPlayerMP mpPlayer = (EntityPlayerMP) event.player; - if ( VendingMachine.proxy.isClient() && !MinecraftServer.getServer() .isDedicatedServer() @@ -130,7 +128,7 @@ public void onServerTick(TickEvent.ServerTickEvent event) { if (!server.isDedicatedServer()) { boolean tmp = openToLAN; - openToLAN = server instanceof IntegratedServer && ((IntegratedServer) server).getPublic(); + openToLAN = server instanceof IntegratedServer iServer && iServer.getPublic(); if (openToLAN && !tmp) opQueue.addAll(server.getConfigurationManager().playerEntityList); } else if (!openToLAN) { openToLAN = true; @@ -164,19 +162,16 @@ private void terminateVendingSession(@Nonnull EntityPlayer player) { return; } if ( - !(player.openContainer instanceof ModularContainer - && ((ModularContainer) player.openContainer).getGuiData() instanceof PosGuiData) + !(player.openContainer instanceof ModularContainer container + && container.getGuiData() instanceof PosGuiData guiData) ) { return; } - TileEntity te = ((PosGuiData) ((ModularContainer) player.openContainer).getGuiData()).getTileEntity(); + TileEntity te = guiData.getTileEntity(); - if ( - te instanceof IGregTechTileEntity - && ((IGregTechTileEntity) te).getMetaTileEntity() instanceof MTEVendingMachine - ) { + if (te instanceof IGregTechTileEntity gte && gte.getMetaTileEntity() instanceof MTEVendingMachine vm) { VendingMachine.LOG.info("Force terminating VM session for {}", player); - ((MTEVendingMachine) ((IGregTechTileEntity) te).getMetaTileEntity()).resetCurrentUser(player); + vm.resetCurrentUser(player); SaveLoadHandler.INSTANCE .writeTradeState(Collections.singleton(NameCache.INSTANCE.getUUIDFromPlayer(player))); } diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java index 299b92d..f5e2454 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java @@ -34,14 +34,11 @@ public void displayNotification(List tradeGroups) { // If player is already accessing a vending machine, don't send notifications if ( - mc.thePlayer.openContainer instanceof ModularContainer - && ((ModularContainer) mc.thePlayer.openContainer).getGuiData() instanceof PosGuiData + mc.thePlayer.openContainer instanceof ModularContainer container + && container.getGuiData() instanceof PosGuiData guiData ) { - TileEntity te = ((PosGuiData) ((ModularContainer) mc.thePlayer.openContainer).getGuiData()).getTileEntity(); - if ( - te instanceof IGregTechTileEntity - && ((IGregTechTileEntity) te).getMetaTileEntity() instanceof MTEVendingMachine - ) { + TileEntity te = guiData.getTileEntity(); + if (te instanceof IGregTechTileEntity gte && gte.getMetaTileEntity() instanceof MTEVendingMachine) { return; } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index f66ee72..1760cc9 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -131,10 +131,7 @@ public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean m NBTTagCompound state = tradeStateList.getCompoundTagAt(i); UUID tgId = NBTConverter.UuidValueType.TRADEGROUP.readId(state); TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); - boolean notificationQueued = false; - if (state.hasKey("notificationQueued")) { - notificationQueued = state.getBoolean("notificationQueued"); - } + boolean notificationQueued = state.getBoolean("notificationQueued"); TradeHistory th = new TradeHistory( state.getLong("lastTrade"), state.getInteger("tradeCount"), From 2b1c447dc82bff59fe7745f3a074594541bfa590 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 23 Dec 2025 13:47:23 +0800 Subject: [PATCH 126/160] Address comments better --- .../cubefury/vendingmachine/handlers/EventHandler.java | 10 +++------- .../vendingmachine/handlers/NotificationHandler.java | 8 +++----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index d2c3d0e..bb7ce6c 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -11,7 +11,6 @@ import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; import net.minecraft.server.integrated.IntegratedServer; -import net.minecraft.tileentity.TileEntity; import net.minecraftforge.event.entity.living.LivingDeathEvent; import org.apache.commons.lang3.Validate; @@ -163,13 +162,10 @@ private void terminateVendingSession(@Nonnull EntityPlayer player) { } if ( !(player.openContainer instanceof ModularContainer container - && container.getGuiData() instanceof PosGuiData guiData) + && container.getGuiData() instanceof PosGuiData guiData + && guiData.getTileEntity() instanceof IGregTechTileEntity gte + && gte.getMetaTileEntity() instanceof MTEVendingMachine vm) ) { - return; - } - TileEntity te = guiData.getTileEntity(); - - if (te instanceof IGregTechTileEntity gte && gte.getMetaTileEntity() instanceof MTEVendingMachine vm) { VendingMachine.LOG.info("Force terminating VM session for {}", player); vm.resetCurrentUser(player); SaveLoadHandler.INSTANCE diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java index f5e2454..a23d642 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/NotificationHandler.java @@ -5,7 +5,6 @@ import java.util.UUID; import net.minecraft.client.Minecraft; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.EnumChatFormatting; @@ -36,11 +35,10 @@ public void displayNotification(List tradeGroups) { if ( mc.thePlayer.openContainer instanceof ModularContainer container && container.getGuiData() instanceof PosGuiData guiData + && guiData.getTileEntity() instanceof IGregTechTileEntity gte + && gte.getMetaTileEntity() instanceof MTEVendingMachine ) { - TileEntity te = guiData.getTileEntity(); - if (te instanceof IGregTechTileEntity gte && gte.getMetaTileEntity() instanceof MTEVendingMachine) { - return; - } + return; } List refreshedTrades = new ArrayList<>(); From 5aa96f4cfca093847bdced3631b493b0a4703187 Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 23 Dec 2025 13:52:33 +0800 Subject: [PATCH 127/160] fix logic error when changing to inline instanceof --- .../com/cubefury/vendingmachine/handlers/EventHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java index bb7ce6c..82c592e 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/EventHandler.java @@ -161,10 +161,10 @@ private void terminateVendingSession(@Nonnull EntityPlayer player) { return; } if ( - !(player.openContainer instanceof ModularContainer container + player.openContainer instanceof ModularContainer container && container.getGuiData() instanceof PosGuiData guiData && guiData.getTileEntity() instanceof IGregTechTileEntity gte - && gte.getMetaTileEntity() instanceof MTEVendingMachine vm) + && gte.getMetaTileEntity() instanceof MTEVendingMachine vm ) { VendingMachine.LOG.info("Force terminating VM session for {}", player); vm.resetCurrentUser(player); From b800f9b1b68827148c35c07bdd6259717d6240ec Mon Sep 17 00:00:00 2001 From: cubefury Date: Tue, 23 Dec 2025 20:19:00 +0800 Subject: [PATCH 128/160] Refactored vending command --- .../command/CommandVending.java | 174 +++--------------- .../vendingmachine/command/Utils.java | 45 +++++ .../command/vending/IVendingSubcommand.java | 17 ++ .../command/vending/SubCmdAdd.java | 105 +++++++++++ .../command/vending/SubCmdReset.java | 98 ++++++++++ .../command/vending/SubCmdSet.java | 103 +++++++++++ 6 files changed, 398 insertions(+), 144 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/command/Utils.java create mode 100644 src/main/java/com/cubefury/vendingmachine/command/vending/IVendingSubcommand.java create mode 100644 src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java create mode 100644 src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReset.java create mode 100644 src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdSet.java diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index dbf3fbc..bf7b78d 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -4,23 +4,30 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; -import net.minecraft.command.PlayerNotFoundException; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.server.MinecraftServer; import net.minecraft.util.ChatComponentText; -import com.cubefury.vendingmachine.storage.NameCache; -import com.cubefury.vendingmachine.trade.CurrencyType; -import com.cubefury.vendingmachine.trade.TradeManager; +import com.cubefury.vendingmachine.command.vending.IVendingSubcommand; +import com.cubefury.vendingmachine.command.vending.SubCmdAdd; +import com.cubefury.vendingmachine.command.vending.SubCmdReset; +import com.cubefury.vendingmachine.command.vending.SubCmdSet; public class CommandVending extends CommandBase { + private static final Map SUBCOMMAND_MAP = new HashMap<>(); + + static { + register(new SubCmdAdd()); + register(new SubCmdSet()); + register(new SubCmdReset()); + } + + private static void register(IVendingSubcommand cmd) { + SUBCOMMAND_MAP.put(cmd.getName(), cmd); + } + @Override public String getCommandName() { return "vending"; @@ -28,7 +35,7 @@ public String getCommandName() { @Override public String getCommandUsage(ICommandSender sender) { - return "/vending [player] [amount]"; + return "/vending <" + String.join("|", SUBCOMMAND_MAP.keySet()) + "> [...] "; } @Override @@ -38,148 +45,27 @@ public boolean canCommandSenderUseCommand(ICommandSender sender) { @Override public List addTabCompletionOptions(ICommandSender sender, String[] args) { - switch (args.length) { - case 1: { - return getListOfStringsMatchingLastWord(args, "set", "add", "reset"); - } - case 2: { - List suggestions = getListOfStringsMatchingLastWord( - args, - MinecraftServer.getServer() - .getAllUsernames()); - suggestions.addAll( - Arrays.stream(CurrencyType.values()) - .map(c -> c.id) - .collect(Collectors.toList())); - suggestions.add("all"); - return suggestions; - } - case 3: { - try { - getPlayer(sender, args[1]); - } catch (PlayerNotFoundException except) { - return null; - } - - List suggestions = Arrays.stream(CurrencyType.values()) - .map(c -> c.id) - .collect(Collectors.toList()); - suggestions.add("all"); - if ( - suggestions.stream() - .anyMatch(s -> s.equals(args[2])) - ) { - return null; - } - return suggestions; - } - default: + if (args.length == 1) { + return getListOfStringsFromIterableMatchingLastWord(args, SUBCOMMAND_MAP.keySet()); + } + if (args.length > 1) { + IVendingSubcommand sub = SUBCOMMAND_MAP.get(args[0]); + if (sub == null) { return null; + } + return sub.tabComplete(sender, Arrays.copyOfRange(args, 1, args.length)); } + return null; } @Override public void processCommand(ICommandSender sender, String[] args) { - if (args.length < 2) { - sender.addChatMessage(new ChatComponentText("Usage: " + getCommandUsage(sender))); - return; - } - - String action = args[0]; - EntityPlayerMP target = null; - - if (args.length > 2 && action.equals("reset") || args.length > 3) { - try { - target = getPlayer(sender, args[1]); - } catch (PlayerNotFoundException ignored) {} - } else if (sender instanceof EntityPlayer) { - target = getCommandSenderAsPlayer(sender); - } - - if (target == null) { - sender.addChatMessage(new ChatComponentText("Could not identify player.")); - return; - } - - if (action.equals("set") || action.equals("add")) { - if (args.length < 3 || args.length > 4) { - sender.addChatMessage(new ChatComponentText("Usage: " + getAddOrSetUsage(sender, args[0]))); - return; - } - - int amount = 0; - try { - amount = Integer.parseInt(args[args.length - 1]); - } catch (NumberFormatException e) { - sender.addChatMessage(new ChatComponentText("Usage: " + getAddOrSetUsage(sender, args[0]))); - return; - } - - int typeOffset = args.length > 3 ? 2 : 1; - CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); - if (type == null && !args[typeOffset].equals("all")) { - sender.addChatMessage(new ChatComponentText("Unknown Currency Type: " + args[typeOffset])); - return; - } - - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); - TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); - Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); - if (args[typeOffset].equals("all")) { - for (CurrencyType cur : CurrencyType.values()) { - coinInventory.put(cur, action.equals("add") ? coinInventory.getOrDefault(cur, 0) + amount : amount); - } - sender.addChatMessage( - new ChatComponentText( - String.format( - "%s %dx all coins for %s", - action.equals("add") ? "Added" : "Set", - amount, - target.getDisplayName()))); - } else { - coinInventory.put(type, action.equals("add") ? coinInventory.getOrDefault(type, 0) + amount : amount); - sender.addChatMessage( - new ChatComponentText( - String.format( - "%s %dx %s coins for %s", - action.equals("add") ? "Added" : "Set", - amount, - type.id, - target.getDisplayName()))); - } - } else if (action.equals("reset")) { - if (args.length > 3) { - sender.addChatMessage(new ChatComponentText("Usage: /vending reset [player] [coin_type|all]")); - return; - } - int typeOffset = args.length > 2 ? 2 : 1; - CurrencyType type = CurrencyType.getTypeFromId(args[typeOffset]); - if (type == null && !args[typeOffset].equals("all")) { - sender.addChatMessage(new ChatComponentText("Unknown Currency Type: " + args[typeOffset])); - return; - } - UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); - TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); - Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); - if (args[typeOffset].equals("all")) { - coinInventory.clear(); - sender.addChatMessage( - new ChatComponentText(String.format("Reset all coins for %s", target.getDisplayName()))); - } else { - coinInventory.remove(type); - sender.addChatMessage( - new ChatComponentText(String.format("Reset %s coins for %s", type.id, target.getDisplayName()))); - } + if (args.length > 0 && SUBCOMMAND_MAP.containsKey(args[0])) { + SUBCOMMAND_MAP.get(args[0]) + .execute(sender, Arrays.copyOfRange(args, 1, args.length)); } else { - sender.addChatMessage(new ChatComponentText("Unknown Action: " + action)); + sender.addChatMessage(new ChatComponentText("Usage: " + getCommandUsage(sender))); } - } - private String getAddOrSetUsage(ICommandSender sender, String arg) { - if (!arg.equals("add") && !arg.equals("set")) { - return getCommandUsage(sender); - } - return "/vending " + arg + " [player] "; - } } diff --git a/src/main/java/com/cubefury/vendingmachine/command/Utils.java b/src/main/java/com/cubefury/vendingmachine/command/Utils.java new file mode 100644 index 0000000..19b5f96 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/command/Utils.java @@ -0,0 +1,45 @@ +package com.cubefury.vendingmachine.command; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import net.minecraft.server.MinecraftServer; + +import com.cubefury.vendingmachine.trade.CurrencyType; + +public class Utils { + + public static List getCoinTypes() { + return Arrays.stream(CurrencyType.values()) + .map(c -> c.id) + .collect(Collectors.toList()); + } + + public static List getCoinTypesOrAll() { + List types = getCoinTypes(); + types.add("all"); + return types; + } + + public static List getCurrentPlayers() { + return Arrays.stream( + MinecraftServer.getServer() + .getAllUsernames()) + .collect(Collectors.toList()); + } + + public static List getPlayersAndCoinTypesOrAll() { + return Stream.concat(getCoinTypesOrAll().stream(), getCurrentPlayers().stream()) + .collect(Collectors.toList()); + } + + public static int parseAmount(String arg) { + try { + return Integer.parseInt(arg); + } catch (NumberFormatException except) { + return 0; + } + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/IVendingSubcommand.java b/src/main/java/com/cubefury/vendingmachine/command/vending/IVendingSubcommand.java new file mode 100644 index 0000000..426538a --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/IVendingSubcommand.java @@ -0,0 +1,17 @@ +package com.cubefury.vendingmachine.command.vending; + +import java.util.List; + +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; + +public interface IVendingSubcommand { + + String getName(); + + String getUsage(ICommandSender sender); + + void execute(ICommandSender sender, String[] args) throws CommandException; + + List tabComplete(ICommandSender sender, String[] args); +} diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java new file mode 100644 index 0000000..ce3f3fd --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java @@ -0,0 +1,105 @@ +package com.cubefury.vendingmachine.command.vending; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.ChatComponentText; + +import com.cubefury.vendingmachine.VendingMachine; +import com.cubefury.vendingmachine.command.Utils; +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.CurrencyType; +import com.cubefury.vendingmachine.trade.TradeManager; + +public class SubCmdAdd implements IVendingSubcommand { + + @Override + public String getName() { + return "add"; + } + + @Override + public String getUsage(ICommandSender sender) { + return "/vending add [player] "; + } + + @Override + public void execute(ICommandSender sender, String[] args) throws CommandException { + EntityPlayerMP target = null; + boolean allCurrency = false; + CurrencyType type = null; + int amount = 0; + VendingMachine.LOG.info(args.length); + + switch (args.length) { + case 2: { + target = CommandBase.getCommandSenderAsPlayer(sender); + allCurrency = args[0].equals("all"); + type = CurrencyType.getTypeFromId(args[0]); + amount = Utils.parseAmount(args[1]); + break; + } + case 3: { + try { + target = CommandBase.getPlayer(sender, args[0]); + allCurrency = args[1].equals("all"); + type = CurrencyType.getTypeFromId(args[1]); + amount = Utils.parseAmount(args[2]); + } catch (PlayerNotFoundException ignored) {} + break; + } + default: + } + boolean validCurrency = allCurrency || type != null; + if (target == null || !validCurrency || amount == 0) { + sender.addChatMessage(new ChatComponentText("Usage: " + getUsage(sender))); + return; + } + + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); + TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); + if (allCurrency) { + for (CurrencyType cur : CurrencyType.values()) { + coinInventory.put(cur, coinInventory.getOrDefault(cur, 0) + amount); + } + sender.addChatMessage( + new ChatComponentText(String.format("Added %dx all coins for %s", amount, target.getDisplayName()))); + } else { + coinInventory.put(type, coinInventory.getOrDefault(type, 0) + amount); + sender.addChatMessage( + new ChatComponentText(String.format("Added %dx %s for %s", amount, type.id, target.getDisplayName()))); + } + } + + @Override + public List tabComplete(ICommandSender sender, String[] args) { + switch (args.length) { + case 0: { + return Utils.getPlayersAndCoinTypesOrAll(); + } + case 1: { + return CommandBase + .getListOfStringsFromIterableMatchingLastWord(args, Utils.getPlayersAndCoinTypesOrAll()); + } + case 2: { + if ( + Utils.getCurrentPlayers() + .contains(args[0]) + ) { + return CommandBase.getListOfStringsFromIterableMatchingLastWord(args, Utils.getCoinTypesOrAll()); + } + } + default: { + return null; + } + } + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReset.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReset.java new file mode 100644 index 0000000..b705c3b --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReset.java @@ -0,0 +1,98 @@ +package com.cubefury.vendingmachine.command.vending; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.ChatComponentText; + +import com.cubefury.vendingmachine.command.Utils; +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.CurrencyType; +import com.cubefury.vendingmachine.trade.TradeManager; + +public class SubCmdReset implements IVendingSubcommand { + + @Override + public String getName() { + return "reset"; + } + + @Override + public String getUsage(ICommandSender sender) { + return "/vending reset [player] "; + } + + @Override + public void execute(ICommandSender sender, String[] args) throws CommandException { + EntityPlayerMP target = null; + boolean allCurrency = false; + CurrencyType type = null; + + switch (args.length) { + case 1: { + target = CommandBase.getCommandSenderAsPlayer(sender); + allCurrency = args[0].equals("all"); + type = CurrencyType.getTypeFromId(args[0]); + break; + } + case 2: { + try { + target = CommandBase.getPlayer(sender, args[0]); + allCurrency = args[1].equals("all"); + type = CurrencyType.getTypeFromId(args[1]); + } catch (PlayerNotFoundException ignored) {} + break; + } + default: + } + boolean validCurrency = allCurrency || type != null; + if (target == null || !validCurrency) { + sender.addChatMessage(new ChatComponentText("Usage: " + getUsage(sender))); + return; + } + + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); + TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); + if (allCurrency) { + coinInventory.clear(); + sender.addChatMessage( + new ChatComponentText(String.format("Reset all coins for %s", target.getDisplayName()))); + } else { + coinInventory.remove(type); + sender.addChatMessage( + new ChatComponentText(String.format("Reset %s for %s", type.id, target.getDisplayName()))); + } + } + + @Override + public List tabComplete(ICommandSender sender, String[] args) { + switch (args.length) { + case 0: { + return Utils.getPlayersAndCoinTypesOrAll(); + } + case 1: { + return CommandBase + .getListOfStringsFromIterableMatchingLastWord(args, Utils.getPlayersAndCoinTypesOrAll()); + } + case 2: { + if ( + Utils.getCurrentPlayers() + .contains(args[0]) + ) { + return CommandBase.getListOfStringsFromIterableMatchingLastWord(args, Utils.getCoinTypesOrAll()); + } + } + default: { + return null; + } + } + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdSet.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdSet.java new file mode 100644 index 0000000..37ad7e2 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdSet.java @@ -0,0 +1,103 @@ +package com.cubefury.vendingmachine.command.vending; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.ChatComponentText; + +import com.cubefury.vendingmachine.command.Utils; +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.CurrencyType; +import com.cubefury.vendingmachine.trade.TradeManager; + +public class SubCmdSet implements IVendingSubcommand { + + @Override + public String getName() { + return "set"; + } + + @Override + public String getUsage(ICommandSender sender) { + return "/vending set [player] "; + } + + @Override + public void execute(ICommandSender sender, String[] args) throws CommandException { + EntityPlayerMP target = null; + boolean allCurrency = false; + CurrencyType type = null; + int amount = 0; + + switch (args.length) { + case 2: { + target = CommandBase.getCommandSenderAsPlayer(sender); + allCurrency = args[0].equals("all"); + type = CurrencyType.getTypeFromId(args[0]); + amount = Utils.parseAmount(args[1]); + break; + } + case 3: { + try { + target = CommandBase.getPlayer(sender, args[0]); + allCurrency = args[1].equals("all"); + type = CurrencyType.getTypeFromId(args[1]); + amount = Utils.parseAmount(args[2]); + } catch (PlayerNotFoundException ignored) {} + break; + } + default: + } + boolean validCurrency = allCurrency || type != null; + if (target == null || !validCurrency || amount == 0) { + sender.addChatMessage(new ChatComponentText("Usage: " + getUsage(sender))); + return; + } + + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(target); + TradeManager.INSTANCE.playerCurrency.putIfAbsent(playerId, new HashMap<>()); + Map coinInventory = TradeManager.INSTANCE.playerCurrency.get(playerId); + if (allCurrency) { + for (CurrencyType cur : CurrencyType.values()) { + coinInventory.put(cur, amount); + } + sender.addChatMessage( + new ChatComponentText(String.format("Set all coins = %d for %s", amount, target.getDisplayName()))); + } else { + coinInventory.put(type, amount); + sender.addChatMessage( + new ChatComponentText(String.format("Set %s = %d for %s", type.id, amount, target.getDisplayName()))); + } + } + + @Override + public List tabComplete(ICommandSender sender, String[] args) { + switch (args.length) { + case 0: { + return Utils.getPlayersAndCoinTypesOrAll(); + } + case 1: { + return CommandBase + .getListOfStringsFromIterableMatchingLastWord(args, Utils.getPlayersAndCoinTypesOrAll()); + } + case 2: { + if ( + Utils.getCurrentPlayers() + .contains(args[0]) + ) { + return CommandBase.getListOfStringsFromIterableMatchingLastWord(args, Utils.getCoinTypesOrAll()); + } + } + default: { + return null; + } + } + } +} From 08b8f8730bf544718d9f721acea0bfed0ba8eefe Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 26 Dec 2025 20:09:59 +0800 Subject: [PATCH 129/160] Move player trade satisfied condition tracking into trade manager --- .../integration/betterquesting/BqAdapter.java | 14 ++- .../vendingmachine/trade/TradeDatabase.java | 8 -- .../vendingmachine/trade/TradeGroup.java | 71 +-------------- .../vendingmachine/trade/TradeGroupState.java | 51 +++++++++++ .../vendingmachine/trade/TradeManager.java | 90 ++++++++++--------- 5 files changed, 109 insertions(+), 125 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java 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 a12091a..64a66cb 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java @@ -10,6 +10,7 @@ import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeGroup; +import com.cubefury.vendingmachine.trade.TradeManager; import com.google.common.collect.ImmutableMap; import cpw.mods.fml.relauncher.Side; @@ -63,7 +64,7 @@ public void setQuestFinished(UUID player, UUID quest) { return; } for (TradeGroup tradeGroup : questUpdateTriggers.get(quest)) { - tradeGroup.addSatisfiedCondition(player, new BqCondition(quest)); + TradeManager.INSTANCE.addSatisfiedCondition(tradeGroup, player, new BqCondition(quest)); } synchronized (playerSatisfiedCache) { playerSatisfiedCache.computeIfAbsent(player, k -> new HashSet<>()); @@ -74,7 +75,7 @@ public void setQuestFinished(UUID player, UUID quest) { public void setQuestUnfinished(UUID player, UUID quest) { for (TradeGroup tradeGroup : questUpdateTriggers.get(quest)) { - tradeGroup.removeSatisfiedCondition(player, new BqCondition(quest)); + TradeManager.INSTANCE.removeSatisfiedCondition(tradeGroup, player, new BqCondition(quest)); synchronized (playerSatisfiedCache) { if (playerSatisfiedCache.get(player) != null) { playerSatisfiedCache.get(player) @@ -85,7 +86,14 @@ public void setQuestUnfinished(UUID player, UUID quest) { } public void resetQuests(UUID player) { - TradeDatabase.INSTANCE.removeAllSatisfiedBqConditions(player); + for (Map.Entry> entry : questUpdateTriggers.entrySet()) { + if (entry.getValue() == null) { + continue; + } + for (TradeGroup tg : entry.getValue()) { + TradeManager.INSTANCE.removeSatisfiedCondition(tg, player, new BqCondition(entry.getKey())); + } + } synchronized (playerSatisfiedCache) { if (player == null) { playerSatisfiedCache.clear(); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 1760cc9..28411e3 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -107,7 +107,6 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge, boolean isFileLoad) { refreshNeiCache(); } - TradeManager.INSTANCE.recomputeAvailableTrades(null); VendingMachine.LOG.info("Loaded {} trade groups containing {} trades.", getTradeGroupCount(), getTradeCount()); } @@ -170,11 +169,4 @@ public void refreshNeiCache() { NeiRecipeCache.refreshCache(); } - @Optional.Method(modid = "betterquesting") - public void removeAllSatisfiedBqConditions(UUID player) { - for (TradeGroup tg : tradeGroups.values()) { - tg.removeAllSatisfiedBqConditions(player); - } - TradeManager.INSTANCE.recomputeAvailableTrades(player); - } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index a186613..a8d975f 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -30,12 +30,7 @@ public class TradeGroup { public int maxTrades = -1; private TradeCategory category = TradeCategory.UNKNOWN; private String original_category_str = ""; - private final Set requirementSet = new HashSet<>(); - - // List of completed conditions for each player - // This is only updated server-side, since players only need to know what trades - // they have and their status. - private final Map> playerDone = new HashMap<>(); + public final Set requirementSet = new HashSet<>(); // List of players with trade history private final Map tradeState = new HashMap<>(); @@ -54,36 +49,6 @@ public boolean hasNoConditions() { return this.requirementSet.isEmpty(); } - public void addSatisfiedCondition(UUID player, ICondition c) { - synchronized (playerDone) { - playerDone.computeIfAbsent(player, k -> new HashSet<>()); - playerDone.get(player) - .add(c); - if ( - playerDone.get(player) - .equals(requirementSet) - ) { - TradeManager.INSTANCE.addTradeGroup(player, this.id); - } - } - } - - public void removeSatisfiedCondition(UUID player, ICondition c) { - synchronized (playerDone) { - if (!playerDone.containsKey(player) || playerDone.get(player) == null) { - return; - } - playerDone.get(player) - .remove(c); - if ( - !playerDone.get(player) - .equals(requirementSet) - ) { - TradeManager.INSTANCE.removeTradeGroup(player, this.id); - } - } - } - public List getTrades() { return trades; } @@ -106,23 +71,6 @@ public void clearTradeState(UUID player) { } } - public boolean isUnlockedPlayer(UUID player) { - return requirementSet.equals(playerDone.getOrDefault(player, new HashSet<>())); - } - - public Set getAllUnlockedPlayers() { - Set playerList = new HashSet<>(); - for (Map.Entry> entry : playerDone.entrySet()) { - if ( - entry.getValue() - .equals(requirementSet) - ) { - playerList.add(entry.getKey()); - } - } - return playerList; - } - public TradeHistory getTradeState(UUID player) { synchronized (tradeState) { if (!tradeState.containsKey(player) || tradeState.get(player) == null) { @@ -232,21 +180,4 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { return nbt; } - @Optional.Method(modid = "betterquesting") - public void removeAllSatisfiedBqConditions(UUID player) { - synchronized (tradeState) { - if (player == null) { - for (Map.Entry> entry : playerDone.entrySet()) { - if (entry.getValue() == null) { // just in case - continue; - } - entry.getValue() - .removeIf((condition) -> condition instanceof BqCondition); - } - } else if (playerDone.get(player) != null) { - playerDone.get(player) - .removeIf((condition) -> condition instanceof BqCondition); - } - } - } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java new file mode 100644 index 0000000..8d6f99b --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java @@ -0,0 +1,51 @@ +package com.cubefury.vendingmachine.trade; + +import com.cubefury.vendingmachine.api.trade.ICondition; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public class TradeGroupState { + + public TradeGroup tradeGroup; + + // List of completed conditions for each player + // This is only updated server-side, since players only need to know what trades + // they have and their status. + private final Map> playerSatisfied = new HashMap<>(); + + // List of players with trade history + private final Map tradeState = new HashMap<>(); + + public TradeGroupState(TradeGroup tradeGroup) { + this.tradeGroup = tradeGroup; + } + + public void addConditionSatisfied(@Nonnull UUID player, ICondition c) { + playerSatisfied.putIfAbsent(player, new HashSet<>()); + playerSatisfied.get(player).add(c); + } + + public void removeConditionSatisfied(@Nullable UUID player, ICondition c) { + if (player == null) { + for (Set conditions : playerSatisfied.values()) { + conditions.remove(c); + } + } else if (playerSatisfied.containsKey(player)) { + playerSatisfied.get(player).remove(c); + } + } + + public boolean satisfiesTrade(@Nonnull UUID player) { + return playerSatisfied.get(player).equals(tradeGroup.getRequirements()); + } + + public Set getPlayersWithConditionData() { + return playerSatisfied.keySet(); + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index f6fb7a2..1337370 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -10,7 +10,9 @@ import java.util.UUID; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import com.cubefury.vendingmachine.api.trade.ICondition; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -22,16 +24,27 @@ import com.cubefury.vendingmachine.network.handlers.NetTradeNotification; import com.cubefury.vendingmachine.storage.NameCache; -// 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 +// Sync the following objects to the client every GUI refresh cycle: +// Available trades, No-condition trades and currency +// Everything else is stored server-side public class TradeManager { public static TradeManager INSTANCE = new TradeManager(); + // availableTrades and noCondition trades technically have information that + // is extractable from tradegroupStates, but querying that every second + // for gui display is more expensive so we cache it here + // only the available trades + currency data is sent to player private final Map> availableTrades = new HashMap<>(); private final List noConditionTrades = new ArrayList<>(); + // Map for tradegroup id -> player trade states and unlock status + public final Map tradeGroupStates = new HashMap<>(); + + // Map for player id -> currency data public final Map> playerCurrency = new HashMap<>(); + + // Map for player id -> trades with pending refresh notifications public final Map> notificationQueue = new HashMap<>(); // For writeback to file in original format, to prevent data loss @@ -43,55 +56,44 @@ public class TradeManager { private TradeManager() {} - public void addTradeGroup(UUID player, UUID tg) { - synchronized (availableTrades) { - if (!availableTrades.containsKey(player) || availableTrades.get(player) == null) { - availableTrades.put(player, new HashSet<>()); - } - availableTrades.get(player) - .add(tg); - } + public void addTradeGroup(@Nonnull UUID player, UUID tg) { + availableTrades.putIfAbsent(player, new HashSet<>()); + availableTrades.get(player).add(tg); } public void removeTradeGroup(UUID player, UUID tg) { - synchronized (availableTrades) { - if (availableTrades.get(player) != null) { - availableTrades.get(player) - .remove(tg); - } + if (availableTrades.containsKey(player)) { + availableTrades.get(player).remove(tg); } } - 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()) { - availableTrades.computeIfAbsent(p, k -> new HashSet<>()); - availableTrades.get(p) - .add(entry.getKey()); - } - } else if ( - entry.getValue() - .isUnlockedPlayer(player) - ) { - availableTrades.computeIfAbsent(player, k -> new HashSet<>()); - availableTrades.get(player) - .add(entry.getKey()); - } + public void addSatisfiedCondition(TradeGroup tradeGroup, @Nonnull UUID player, ICondition c) { + UUID tradeGroupId = tradeGroup.getId(); + tradeGroupStates.putIfAbsent(tradeGroupId, new TradeGroupState(tradeGroup)); + tradeGroupStates.get(tradeGroupId).addConditionSatisfied(player, c); + + updateAvailableTrades(tradeGroupId, player); + } + + public void removeSatisfiedCondition(TradeGroup tradeGroup, @Nullable UUID player, ICondition c) { + UUID tradeGroupId = tradeGroup.getId(); + tradeGroupStates.putIfAbsent(tradeGroupId, new TradeGroupState(tradeGroup)); + tradeGroupStates.get(tradeGroupId).removeConditionSatisfied(player, c); + + if (player == null) { + for (UUID p : tradeGroupStates.get(tradeGroupId).getPlayersWithConditionData()) { + updateAvailableTrades(tradeGroupId, p); } + } else { + updateAvailableTrades(tradeGroupId, player); + } + } + + private void updateAvailableTrades(UUID tradeGroupId, @Nullable UUID player) { + if (tradeGroupStates.get(tradeGroupId).satisfiesTrade(player)) { + TradeManager.INSTANCE.addTradeGroup(player, tradeGroupId); + } else { + TradeManager.INSTANCE.removeTradeGroup(player, tradeGroupId); } } From f6e692f06331dbe504701f091a148a1dee72750b Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 26 Dec 2025 21:16:20 +0800 Subject: [PATCH 130/160] Swap noconditiontrades to tradedatabase --- .../com/cubefury/vendingmachine/trade/TradeDatabase.java | 6 ++++++ .../com/cubefury/vendingmachine/trade/TradeManager.java | 4 +--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 28411e3..571d30f 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -32,9 +32,12 @@ public class TradeDatabase { private final Map tradeGroups = new HashMap<>(); private final Map> tradeCategories = new HashMap<>(); + public final List noConditionTrades = new ArrayList<>(); + private TradeDatabase() {} public void clear() { + noConditionTrades.clear(); tradeGroups.clear(); tradeCategories.clear(); } @@ -93,6 +96,9 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge, boolean isFileLoad) { VendingMachine.LOG.error("Multiple trade groups with id {} exist in the file!", tg); continue; } + if (tg.hasNoConditions()) { + noConditionTrades.add(tg); + } tradeCategories.computeIfAbsent(tg.getCategory(), k -> new HashSet<>()); tradeCategories.get(tg.getCategory()) .add(tg.getId()); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 1337370..be87e49 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -36,7 +36,6 @@ public class TradeManager { // for gui display is more expensive so we cache it here // only the available trades + currency data is sent to player private final Map> availableTrades = new HashMap<>(); - private final List noConditionTrades = new ArrayList<>(); // Map for tradegroup id -> player trade states and unlock status public final Map tradeGroupStates = new HashMap<>(); @@ -100,12 +99,11 @@ private void updateAvailableTrades(UUID tradeGroupId, @Nullable UUID player) { public List getAvailableTradeGroups(UUID player) { synchronized (availableTrades) { availableTrades.computeIfAbsent(player, k -> new HashSet<>()); - availableTrades.get(player) - .addAll(noConditionTrades); ArrayList tradeList = new ArrayList<>(); for (UUID tgId : availableTrades.get(player)) { tradeList.add(TradeDatabase.INSTANCE.getTradeGroupFromId(tgId)); } + tradeList.addAll(TradeDatabase.INSTANCE.noConditionTrades); return tradeList; } } From e37233f4b394d00787f33ed57f7e4f0cc86e8d06 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 27 Dec 2025 16:05:40 +0800 Subject: [PATCH 131/160] Swap tradestate tracking to TradeManager --- .../blocks/MTEVendingMachine.java | 13 ++- .../handlers/SaveLoadHandler.java | 6 +- .../network/handlers/NetTradeDisplaySync.java | 6 +- .../vendingmachine/trade/TradeDatabase.java | 49 ---------- .../vendingmachine/trade/TradeGroup.java | 64 ------------ .../vendingmachine/trade/TradeGroupState.java | 16 +++ .../vendingmachine/trade/TradeManager.java | 98 ++++++++++++++++++- .../vendingmachine/util/JsonHelper.java | 3 +- 8 files changed, 125 insertions(+), 130 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 9cc51b8..9493d94 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -244,10 +244,9 @@ public void dispenseItems() { private boolean processTradeOnServer(TradeRequest tradeRequest) { if ( - tradeRequest == null || !TradeDatabase.INSTANCE.getTradeGroups() - .get(tradeRequest.tradeGroup) - .canExecuteTrade(tradeRequest.playerID) - ) { + tradeRequest == null || !TradeManager.INSTANCE.canExecuteTrade( + tradeRequest.playerID, + TradeDatabase.INSTANCE.getTradeGroupFromId(tradeRequest.tradeGroup))) { return false; } this.refreshInputSlotCache(); @@ -358,9 +357,9 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { this.outputBuffer.addAll(toItem.getCombinedStacks()); this.newBufferedOutputs = true; } - TradeDatabase.INSTANCE.getTradeGroups() - .get(tradeRequest.tradeGroup) - .executeTrade(tradeRequest.playerID); + TradeManager.INSTANCE.executeTrade(tradeRequest.playerID, + TradeDatabase.INSTANCE.getTradeGroups() + .get(tradeRequest.tradeGroup)); this.sendTradeUpdate(); this.markDirty(); return true; diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 3f6cbdc..af34d20 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -12,6 +12,7 @@ import java.util.concurrent.Future; import java.util.stream.Collectors; +import com.cubefury.vendingmachine.trade.TradeManager; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.server.MinecraftServer; @@ -104,12 +105,11 @@ public List> writeTradeState(Collection players) { CopyPaste(dirTradeState, dirBackupTradeState); } - TradeDatabase db = TradeDatabase.INSTANCE; List> futures = new ArrayList<>(); for (UUID player : players) { File playerFile = new File(dirTradeState, player.toString() + ".json"); CopyPaste(playerFile, new File(dirBackupTradeState, player.toString() + ".json")); - NBTTagCompound state = db.writeTradeStateToNBT(new NBTTagCompound(), player); + NBTTagCompound state = TradeManager.INSTANCE.writeTradeStateToNBT(new NBTTagCompound(), player); futures.add(FileIO.WriteToFile(playerFile, out -> NBTConverter.NBTtoJSON_Compound(state, out, true))); } return futures; @@ -128,7 +128,7 @@ public Future writeNames() { public void unloadAll() { NameCache.INSTANCE.clear(); TradeDatabase.INSTANCE.clear(); - TradeDatabase.INSTANCE.clearTradeState(null); + TradeManager.INSTANCE.clearTradeState(null); } } 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 4ac7275..44f37a0 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java @@ -5,6 +5,7 @@ import javax.annotation.Nonnull; +import com.cubefury.vendingmachine.trade.TradeHistory; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -119,8 +120,9 @@ public static void syncTradesToClient(@Nonnull EntityPlayerMP player, MTEVending NBTTagCompound payload = new NBTTagCompound(); NBTTagList trades = new NBTTagList(); for (TradeGroup tg : availableGroups) { - long lastTradeTime = tg.getTradeState(playerId).lastTrade; - long tradeCount = tg.getTradeState(playerId).tradeCount; + TradeHistory history = TradeManager.INSTANCE.getTradeState(playerId, tg); + long lastTradeTime = history.lastTrade; + long tradeCount = history.tradeCount; long cooldownRemaining; if (tg.cooldown != -1 && lastTradeTime != -1 && (currentTimestamp - lastTradeTime) / 1000 < tg.cooldown) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 571d30f..5523306 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -42,12 +42,6 @@ public void clear() { tradeCategories.clear(); } - public void clearTradeState(UUID player) { - tradeGroups.forEach((k, v) -> v.clearTradeState(player)); - TradeManager.INSTANCE.clearCurrency(player); - TradeManager.INSTANCE.clearNotificationQueue(player); - } - public TradeGroup getTradeGroupFromId(UUID tgId) { return tradeGroups.get(tgId); } @@ -127,49 +121,6 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { return nbt; } - public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean merge) { - NBTTagList tradeStateList = nbt.getTagList("tradeState", Constants.NBT.TAG_COMPOUND); - if (!merge) { - clearTradeState(player); - } - for (int i = 0; i < tradeStateList.tagCount(); i++) { - NBTTagCompound state = tradeStateList.getCompoundTagAt(i); - UUID tgId = NBTConverter.UuidValueType.TRADEGROUP.readId(state); - TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); - boolean notificationQueued = state.getBoolean("notificationQueued"); - TradeHistory th = new TradeHistory( - state.getLong("lastTrade"), - state.getInteger("tradeCount"), - notificationQueued); - if (tg != null) { - tg.setTradeState(player, th); - if (notificationQueued) { - TradeManager.INSTANCE.addNotification(player, tg); - } - } - } - TradeManager.INSTANCE.populateCurrencyFromNBT(nbt, player, merge); - } - - public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, @Nonnull UUID player) { - NBTTagList tradeStateList = new NBTTagList(); - for (Map.Entry entry : tradeGroups.entrySet()) { - TradeHistory history = entry.getValue() - .getTradeState(player); - if (!history.equals(TradeHistory.DEFAULT)) { - NBTTagCompound state = new NBTTagCompound(); - NBTConverter.UuidValueType.TRADEGROUP.writeId(entry.getKey(), state); - state.setLong("lastTrade", history.lastTrade); - state.setInteger("tradeCount", history.tradeCount); - state.setBoolean("notificationQueued", history.notificationQueued); - tradeStateList.appendTag(state); - } - } - nbt.setTag("tradeState", tradeStateList); - TradeManager.INSTANCE.writeCurrencyToNBT(nbt, player); - return nbt; - } - @SideOnly(Side.CLIENT) public void refreshNeiCache() { NeiRecipeCache.refreshCache(); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index a8d975f..31f0303 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -32,9 +32,6 @@ public class TradeGroup { private String original_category_str = ""; public final Set requirementSet = new HashSet<>(); - // List of players with trade history - private final Map tradeState = new HashMap<>(); - public TradeGroup() {} public UUID getId() { @@ -61,67 +58,6 @@ public List getRequirements() { return new ArrayList<>(requirementSet); } - public void clearTradeState(UUID player) { - synchronized (tradeState) { - if (player == null) { - tradeState.clear(); - } else { - tradeState.remove(player); - } - } - } - - public TradeHistory getTradeState(UUID player) { - synchronized (tradeState) { - if (!tradeState.containsKey(player) || tradeState.get(player) == null) { - return new TradeHistory(); - } - return tradeState.get(player); - } - } - - public void setTradeState(UUID player, TradeHistory history) { - synchronized (tradeState) { - tradeState.put(player, history); - - } - } - - public boolean canExecuteTrade(UUID player) { - 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.id.equals(this.id) && enabled && cooldownRemaining < 0) { - return true; - } - } - return false; - } - - public void executeTrade(UUID player) { - TradeHistory newTradeHistory = getTradeState(player); - newTradeHistory.executeTrade(maxTrades, this.cooldown != -1); - setTradeState(player, newTradeHistory); - SaveLoadHandler.INSTANCE.writeTradeState(Collections.singleton(player)); - if (newTradeHistory.notificationQueued) { - TradeManager.INSTANCE.addNotification(player, this); - } - } - public boolean readFromNBT(NBTTagCompound nbt) { this.trades.clear(); this.requirementSet.clear(); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java index 8d6f99b..34ec1a0 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java @@ -26,6 +26,22 @@ public TradeGroupState(TradeGroup tradeGroup) { this.tradeGroup = tradeGroup; } + public void clearTradeState(@Nullable UUID player) { + if (player == null) { + tradeState.clear(); + } else { + tradeState.remove(player); + } + } + + public void setTradeState(@Nonnull UUID player, TradeHistory history) { + tradeState.put(player, history); + } + + public TradeHistory getTradeState(@Nonnull UUID player) { + return tradeState.getOrDefault(player, new TradeHistory()); + } + public void addConditionSatisfied(@Nonnull UUID player, ICondition c) { playerSatisfied.putIfAbsent(player, new HashSet<>()); playerSatisfied.get(player).add(c); diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index be87e49..30c9337 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -13,6 +13,7 @@ import javax.annotation.Nullable; import com.cubefury.vendingmachine.api.trade.ICondition; +import com.cubefury.vendingmachine.util.NBTConverter; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -25,7 +26,7 @@ import com.cubefury.vendingmachine.storage.NameCache; // Sync the following objects to the client every GUI refresh cycle: -// Available trades, No-condition trades and currency +// tradedata, No-condition trades and currency // Everything else is stored server-side public class TradeManager { @@ -90,9 +91,9 @@ public void removeSatisfiedCondition(TradeGroup tradeGroup, @Nullable UUID playe private void updateAvailableTrades(UUID tradeGroupId, @Nullable UUID player) { if (tradeGroupStates.get(tradeGroupId).satisfiesTrade(player)) { - TradeManager.INSTANCE.addTradeGroup(player, tradeGroupId); + addTradeGroup(player, tradeGroupId); } else { - TradeManager.INSTANCE.removeTradeGroup(player, tradeGroupId); + removeTradeGroup(player, tradeGroupId); } } @@ -158,6 +159,95 @@ public NBTTagCompound writeCurrencyToNBT(NBTTagCompound nbt, @Nonnull UUID playe return nbt; } + public void clearTradeState(@Nullable UUID player) { + tradeGroupStates.forEach((uuid, tgs) -> tgs.clearTradeState(player)); + clearCurrency(player); + clearNotificationQueue(player); + } + + public TradeHistory getTradeState(@Nonnull UUID player, TradeGroup tg) { + tradeGroupStates.putIfAbsent(tg.getId(), new TradeGroupState(tg)); + return tradeGroupStates.get(tg.getId()).getTradeState(player); + } + + public void setTradeState(@Nonnull UUID player, TradeGroup tg, TradeHistory history) { + tradeGroupStates.putIfAbsent(tg.getId(), new TradeGroupState(tg)); + tradeGroupStates.get(tg.getId()).setTradeState(player, history); + } + + public boolean canExecuteTrade(@Nonnull UUID player, TradeGroup tg) { + long currentTimestamp = System.currentTimeMillis(); + TradeHistory history = getTradeState(player, tg); + long lastTradeTime = history.lastTrade; + long tradeCount = history.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; + + return availableTrades.getOrDefault(player, Collections.emptySet()).contains(tg.getId()) + && enabled + && cooldownRemaining < 0; + } + + public void executeTrade(@Nonnull UUID player, TradeGroup tg) { + TradeHistory newTradeHistory = getTradeState(player, tg); + newTradeHistory.executeTrade(tg.maxTrades, tg.cooldown != -1); + setTradeState(player, tg, newTradeHistory); + SaveLoadHandler.INSTANCE.writeTradeState(Collections.singleton(player)); + if (newTradeHistory.notificationQueued) { + addNotification(player, tg); + } + } + + public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean merge) { + NBTTagList tradeStateList = nbt.getTagList("tradeState", Constants.NBT.TAG_COMPOUND); + if (!merge) { + clearTradeState(player); + } + for (int i = 0; i < tradeStateList.tagCount(); i++) { + NBTTagCompound state = tradeStateList.getCompoundTagAt(i); + UUID tgId = NBTConverter.UuidValueType.TRADEGROUP.readId(state); + TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(tgId); + boolean notificationQueued = state.getBoolean("notificationQueued"); + TradeHistory th = new TradeHistory( + state.getLong("lastTrade"), + state.getInteger("tradeCount"), + notificationQueued); + if (tg != null) { + tradeGroupStates.putIfAbsent(tg.getId(), new TradeGroupState(tg)); + tradeGroupStates.get(tg.getId()).setTradeState(player, th); + if (notificationQueued) { + addNotification(player, tg); + } + } + } + populateCurrencyFromNBT(nbt, player, merge); + } + + public NBTTagCompound writeTradeStateToNBT(NBTTagCompound nbt, @Nonnull UUID player) { + NBTTagList tradeStateList = new NBTTagList(); + for (Map.Entry entry : tradeGroupStates.entrySet()) { + TradeHistory history = entry.getValue() + .getTradeState(player); + if (!history.equals(TradeHistory.DEFAULT)) { + NBTTagCompound state = new NBTTagCompound(); + NBTConverter.UuidValueType.TRADEGROUP.writeId(entry.getKey(), state); + state.setLong("lastTrade", history.lastTrade); + state.setInteger("tradeCount", history.tradeCount); + state.setBoolean("notificationQueued", history.notificationQueued); + tradeStateList.appendTag(state); + } + } + nbt.setTag("tradeState", tradeStateList); + writeCurrencyToNBT(nbt, player); + return nbt; + } + public void resetCurrency(UUID playerId, CurrencyType type) { this.playerCurrency.computeIfAbsent(playerId, k -> new HashMap<>()); if (type == null) { @@ -223,7 +313,7 @@ public void sendTradeNotifications(EntityPlayerMP player) { if (tradeGroup == null) { continue; } - TradeHistory th = tradeGroup.getTradeState(playerId); + TradeHistory th = getTradeState(playerId, tradeGroup); if ((currentTimestamp - th.lastTrade) / 1000 > tradeGroup.cooldown) { notifList.add(tgId); th.setNotified(); diff --git a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java index f3390d0..e5bc30d 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java +++ b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java @@ -8,6 +8,7 @@ import javax.annotation.Nonnull; +import com.cubefury.vendingmachine.trade.TradeManager; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.Constants; @@ -64,7 +65,7 @@ public static void populateTradeStateFromFiles(List files) { public static void populateTradeStateFromFile(File file) { JsonObject json = FileIO.ReadFromFile(file); NBTTagCompound nbt = NBTConverter.JSONtoNBT_Object(json, new NBTTagCompound(), true); - TradeDatabase.INSTANCE.populateTradeStateFromNBT(nbt, UUID.fromString(FileIO.getFileName(file)), false); + TradeManager.INSTANCE.populateTradeStateFromNBT(nbt, UUID.fromString(FileIO.getFileName(file)), false); } public static void populateNameCacheFromFile(File file) { From a0e453952583aaa57838d1ab6c7afa4e4ad70db3 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 27 Dec 2025 16:20:40 +0800 Subject: [PATCH 132/160] Some comments --- .../integration/betterquesting/BqAdapter.java | 6 +++--- .../network/handlers/NetSatisfiedQuestSync.java | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) 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 64a66cb..03d1e44 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/betterquesting/BqAdapter.java @@ -8,7 +8,6 @@ import javax.annotation.Nullable; -import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeGroup; import com.cubefury.vendingmachine.trade.TradeManager; import com.google.common.collect.ImmutableMap; @@ -24,6 +23,7 @@ public class BqAdapter { // cache of quests that player has completed, for NEI integration not having // to look it up so much + // Server calculates this cache and syncs it directly to players private final Map> playerSatisfiedCache = new HashMap<>(); private BqAdapter() {} @@ -51,7 +51,7 @@ public Map> getPlayerSatisfiedCache() { } @SideOnly(Side.CLIENT) - public void setPlayerSatisifedCache(Map> newCache) { + public void setPlayerSatisfiedCache(Map> newCache) { // Player -> Set synchronized (playerSatisfiedCache) { playerSatisfiedCache.clear(); @@ -67,7 +67,7 @@ public void setQuestFinished(UUID player, UUID quest) { TradeManager.INSTANCE.addSatisfiedCondition(tradeGroup, player, new BqCondition(quest)); } synchronized (playerSatisfiedCache) { - playerSatisfiedCache.computeIfAbsent(player, k -> new HashSet<>()); + playerSatisfiedCache.putIfAbsent(player, new HashSet<>()); playerSatisfiedCache.get(player) .add(quest); } diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java index dc1a561..732a8ea 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java @@ -68,6 +68,7 @@ public static void onClient(NBTTagCompound message) { Minecraft.getMinecraft() .isIntegratedServerRunning() ) { + // Don't override in singleplayer or on LAN return; } @@ -80,6 +81,6 @@ public static void onClient(NBTTagCompound message) { newCache.get(playerId) .add(NBTConverter.UuidValueType.QUEST.readId(questList.getCompoundTagAt(i))); } - BqAdapter.INSTANCE.setPlayerSatisifedCache(newCache); + BqAdapter.INSTANCE.setPlayerSatisfiedCache(newCache); } } From ec838adc33a87459f092514791d4a2f5a93b941c Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 27 Dec 2025 16:21:08 +0800 Subject: [PATCH 133/160] spotless --- .../blocks/MTEVendingMachine.java | 6 ++- .../handlers/SaveLoadHandler.java | 2 +- .../network/handlers/NetTradeDisplaySync.java | 2 +- .../vendingmachine/trade/TradeDatabase.java | 4 -- .../vendingmachine/trade/TradeGroup.java | 6 --- .../vendingmachine/trade/TradeGroupState.java | 18 +++++---- .../vendingmachine/trade/TradeManager.java | 37 ++++++++++++------- .../vendingmachine/util/JsonHelper.java | 2 +- 8 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 9493d94..3eccf42 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -246,7 +246,8 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { if ( tradeRequest == null || !TradeManager.INSTANCE.canExecuteTrade( tradeRequest.playerID, - TradeDatabase.INSTANCE.getTradeGroupFromId(tradeRequest.tradeGroup))) { + TradeDatabase.INSTANCE.getTradeGroupFromId(tradeRequest.tradeGroup)) + ) { return false; } this.refreshInputSlotCache(); @@ -357,7 +358,8 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { this.outputBuffer.addAll(toItem.getCombinedStacks()); this.newBufferedOutputs = true; } - TradeManager.INSTANCE.executeTrade(tradeRequest.playerID, + TradeManager.INSTANCE.executeTrade( + tradeRequest.playerID, TradeDatabase.INSTANCE.getTradeGroups() .get(tradeRequest.tradeGroup)); this.sendTradeUpdate(); diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index af34d20..9678b38 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -12,7 +12,6 @@ import java.util.concurrent.Future; import java.util.stream.Collectors; -import com.cubefury.vendingmachine.trade.TradeManager; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.server.MinecraftServer; @@ -21,6 +20,7 @@ import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.FileIO; import com.cubefury.vendingmachine.util.JsonHelper; import com.cubefury.vendingmachine.util.NBTConverter; 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 44f37a0..576b5a7 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 com.cubefury.vendingmachine.trade.TradeHistory; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -23,6 +22,7 @@ import com.cubefury.vendingmachine.trade.Trade; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeGroup; +import com.cubefury.vendingmachine.trade.TradeHistory; import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.NBTConverter; import com.cubefury.vendingmachine.util.Translator; diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 5523306..232f4a3 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -9,8 +9,6 @@ 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; @@ -19,9 +17,7 @@ import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.integration.betterquesting.BqAdapter; import com.cubefury.vendingmachine.integration.nei.NeiRecipeCache; -import com.cubefury.vendingmachine.util.NBTConverter; -import cpw.mods.fml.common.Optional; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index 31f0303..f3acacb 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -1,11 +1,8 @@ package com.cubefury.vendingmachine.trade; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.UUID; @@ -15,13 +12,10 @@ import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.api.trade.ICondition; -import com.cubefury.vendingmachine.handlers.SaveLoadHandler; import com.cubefury.vendingmachine.integration.betterquesting.BqAdapter; import com.cubefury.vendingmachine.integration.betterquesting.BqCondition; import com.cubefury.vendingmachine.util.NBTConverter; -import cpw.mods.fml.common.Optional; - public class TradeGroup { private UUID id = new UUID(0, 0); // placeholder UUID diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java index 34ec1a0..c9590d0 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroupState.java @@ -1,15 +1,16 @@ package com.cubefury.vendingmachine.trade; -import com.cubefury.vendingmachine.api.trade.ICondition; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.cubefury.vendingmachine.api.trade.ICondition; + public class TradeGroupState { public TradeGroup tradeGroup; @@ -44,7 +45,8 @@ public TradeHistory getTradeState(@Nonnull UUID player) { public void addConditionSatisfied(@Nonnull UUID player, ICondition c) { playerSatisfied.putIfAbsent(player, new HashSet<>()); - playerSatisfied.get(player).add(c); + playerSatisfied.get(player) + .add(c); } public void removeConditionSatisfied(@Nullable UUID player, ICondition c) { @@ -53,12 +55,14 @@ public void removeConditionSatisfied(@Nullable UUID player, ICondition c) { conditions.remove(c); } } else if (playerSatisfied.containsKey(player)) { - playerSatisfied.get(player).remove(c); + playerSatisfied.get(player) + .remove(c); } } public boolean satisfiesTrade(@Nonnull UUID player) { - return playerSatisfied.get(player).equals(tradeGroup.getRequirements()); + return playerSatisfied.get(player) + .equals(tradeGroup.getRequirements()); } public Set getPlayersWithConditionData() { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 30c9337..0413f61 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -12,18 +12,18 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import com.cubefury.vendingmachine.api.trade.ICondition; -import com.cubefury.vendingmachine.util.NBTConverter; import net.minecraft.entity.player.EntityPlayerMP; 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.api.trade.ICondition; import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplay; import com.cubefury.vendingmachine.handlers.SaveLoadHandler; import com.cubefury.vendingmachine.network.handlers.NetTradeNotification; import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.util.NBTConverter; // Sync the following objects to the client every GUI refresh cycle: // tradedata, No-condition trades and currency @@ -58,19 +58,22 @@ private TradeManager() {} public void addTradeGroup(@Nonnull UUID player, UUID tg) { availableTrades.putIfAbsent(player, new HashSet<>()); - availableTrades.get(player).add(tg); + availableTrades.get(player) + .add(tg); } public void removeTradeGroup(UUID player, UUID tg) { if (availableTrades.containsKey(player)) { - availableTrades.get(player).remove(tg); + availableTrades.get(player) + .remove(tg); } } public void addSatisfiedCondition(TradeGroup tradeGroup, @Nonnull UUID player, ICondition c) { UUID tradeGroupId = tradeGroup.getId(); tradeGroupStates.putIfAbsent(tradeGroupId, new TradeGroupState(tradeGroup)); - tradeGroupStates.get(tradeGroupId).addConditionSatisfied(player, c); + tradeGroupStates.get(tradeGroupId) + .addConditionSatisfied(player, c); updateAvailableTrades(tradeGroupId, player); } @@ -78,10 +81,12 @@ public void addSatisfiedCondition(TradeGroup tradeGroup, @Nonnull UUID player, I public void removeSatisfiedCondition(TradeGroup tradeGroup, @Nullable UUID player, ICondition c) { UUID tradeGroupId = tradeGroup.getId(); tradeGroupStates.putIfAbsent(tradeGroupId, new TradeGroupState(tradeGroup)); - tradeGroupStates.get(tradeGroupId).removeConditionSatisfied(player, c); + tradeGroupStates.get(tradeGroupId) + .removeConditionSatisfied(player, c); if (player == null) { - for (UUID p : tradeGroupStates.get(tradeGroupId).getPlayersWithConditionData()) { + for (UUID p : tradeGroupStates.get(tradeGroupId) + .getPlayersWithConditionData()) { updateAvailableTrades(tradeGroupId, p); } } else { @@ -90,7 +95,10 @@ public void removeSatisfiedCondition(TradeGroup tradeGroup, @Nullable UUID playe } private void updateAvailableTrades(UUID tradeGroupId, @Nullable UUID player) { - if (tradeGroupStates.get(tradeGroupId).satisfiesTrade(player)) { + if ( + tradeGroupStates.get(tradeGroupId) + .satisfiesTrade(player) + ) { addTradeGroup(player, tradeGroupId); } else { removeTradeGroup(player, tradeGroupId); @@ -167,12 +175,14 @@ public void clearTradeState(@Nullable UUID player) { public TradeHistory getTradeState(@Nonnull UUID player, TradeGroup tg) { tradeGroupStates.putIfAbsent(tg.getId(), new TradeGroupState(tg)); - return tradeGroupStates.get(tg.getId()).getTradeState(player); + return tradeGroupStates.get(tg.getId()) + .getTradeState(player); } public void setTradeState(@Nonnull UUID player, TradeGroup tg, TradeHistory history) { tradeGroupStates.putIfAbsent(tg.getId(), new TradeGroupState(tg)); - tradeGroupStates.get(tg.getId()).setTradeState(player, history); + tradeGroupStates.get(tg.getId()) + .setTradeState(player, history); } public boolean canExecuteTrade(@Nonnull UUID player, TradeGroup tg) { @@ -189,8 +199,8 @@ public boolean canExecuteTrade(@Nonnull UUID player, TradeGroup tg) { boolean enabled = tg.maxTrades == -1 || tradeCount < tg.maxTrades; - return availableTrades.getOrDefault(player, Collections.emptySet()).contains(tg.getId()) - && enabled + return availableTrades.getOrDefault(player, Collections.emptySet()) + .contains(tg.getId()) && enabled && cooldownRemaining < 0; } @@ -220,7 +230,8 @@ public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean m notificationQueued); if (tg != null) { tradeGroupStates.putIfAbsent(tg.getId(), new TradeGroupState(tg)); - tradeGroupStates.get(tg.getId()).setTradeState(player, th); + tradeGroupStates.get(tg.getId()) + .setTradeState(player, th); if (notificationQueued) { addNotification(player, tg); } diff --git a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java index e5bc30d..c6eaa48 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java +++ b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java @@ -8,13 +8,13 @@ import javax.annotation.Nonnull; -import com.cubefury.vendingmachine.trade.TradeManager; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.Constants; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeManager; import com.google.gson.JsonObject; public class JsonHelper { From 1f2a19844d5a180b6fa85345992e446a0e697d4e Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 27 Dec 2025 16:23:07 +0800 Subject: [PATCH 134/160] minor comments --- .../java/com/cubefury/vendingmachine/trade/TradeManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 0413f61..c722d74 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -35,7 +35,6 @@ public class TradeManager { // availableTrades and noCondition trades technically have information that // is extractable from tradegroupStates, but querying that every second // for gui display is more expensive so we cache it here - // only the available trades + currency data is sent to player private final Map> availableTrades = new HashMap<>(); // Map for tradegroup id -> player trade states and unlock status From 78600ffdbfcf304cabd621868d5c4b44effca88f Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 31 Dec 2025 17:02:20 +0800 Subject: [PATCH 135/160] Fixed requirement matching bug --- .../cubefury/vendingmachine/trade/TradeGroup.java | 4 ++-- .../vendingmachine/trade/TradeManager.java | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java index f3acacb..77e02dd 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeGroup.java @@ -48,8 +48,8 @@ public TradeCategory getCategory() { return category; } - public List getRequirements() { - return new ArrayList<>(requirementSet); + public Set getRequirements() { + return requirementSet; } public boolean readFromNBT(NBTTagCompound nbt) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index c722d74..568c735 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -105,15 +105,13 @@ private void updateAvailableTrades(UUID tradeGroupId, @Nullable UUID player) { } public List getAvailableTradeGroups(UUID player) { - synchronized (availableTrades) { - availableTrades.computeIfAbsent(player, k -> new HashSet<>()); - ArrayList tradeList = new ArrayList<>(); - for (UUID tgId : availableTrades.get(player)) { - tradeList.add(TradeDatabase.INSTANCE.getTradeGroupFromId(tgId)); - } - tradeList.addAll(TradeDatabase.INSTANCE.noConditionTrades); - return tradeList; + availableTrades.putIfAbsent(player, new HashSet<>()); + ArrayList tradeList = new ArrayList<>(); + for (UUID tgId : availableTrades.get(player)) { + tradeList.add(TradeDatabase.INSTANCE.getTradeGroupFromId(tgId)); } + tradeList.addAll(TradeDatabase.INSTANCE.noConditionTrades); + return tradeList; } public void populateCurrencyFromNBT(NBTTagCompound nbt, UUID player, boolean merge) { From 846a5aeff167bdbc7cc3dd7ca180852b473b5d09 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 31 Dec 2025 17:08:42 +0800 Subject: [PATCH 136/160] minor formatting --- .../java/com/cubefury/vendingmachine/trade/TradeDatabase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index 232f4a3..a912adc 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -83,7 +83,7 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge, boolean isFileLoad) { TradeGroup tg = new TradeGroup(); newMetadataCount += tg.readFromNBT(trades.getCompoundTagAt(i)) ? 1 : 0; if (tradeGroups.containsKey(tg.getId())) { - VendingMachine.LOG.error("Multiple trade groups with id {} exist in the file!", tg); + VendingMachine.LOG.error("Multiple trade groups with id {} exist in the file!", tg.getId()); continue; } if (tg.hasNoConditions()) { From 7edeed58d2e767c5d2918b29e41953662b4cb126 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 31 Dec 2025 17:24:33 +0800 Subject: [PATCH 137/160] Fixed completed quest sync in MP --- .../vendingmachine/network/handlers/NetSatisfiedQuestSync.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java index 732a8ea..b38a9ba 100644 --- a/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java +++ b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetSatisfiedQuestSync.java @@ -52,7 +52,7 @@ public static void sendSync() { if (cache != null && cache.get(playerId) != null) { for (UUID quest : cache.get(playerId)) { NBTTagCompound questInfo = new NBTTagCompound(); - NBTConverter.UuidValueType.QUEST.writeId(quest); + NBTConverter.UuidValueType.QUEST.writeId(quest, questInfo); questList.appendTag(questInfo); } } From 8cbb4fbfc609353a3912add826fa54d9a8ee4eeb Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Thu, 1 Jan 2026 20:07:43 +0100 Subject: [PATCH 138/160] update bs+deps+gradle --- dependencies.gradle | 10 +++++----- gradle.properties | 7 +++++++ gradle/gradle-daemon-jvm.properties | 12 ++++++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 43764 -> 45633 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 5 +---- gradlew.bat | 3 +-- settings.gradle.kts | 2 +- 8 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 gradle/gradle-daemon-jvm.properties diff --git a/dependencies.gradle b/dependencies.gradle index 6bfec3d..1d3aa0e 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.43-GTNH:dev") - implementation("com.github.GTNewHorizons:GTNHLib:0.8.34:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.48-GTNH:dev") + implementation("com.github.GTNewHorizons:GTNHLib:0.8.41:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.14-GTNH:dev") implementation("com.github.GTNewHorizons:ModularUI2:2.3.24-1.7.10:dev") - implementation("com.github.GTNewHorizons:StructureLib:1.4.24:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.154:dev") + implementation("com.github.GTNewHorizons:StructureLib:1.4.25:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.179:dev") } // deps may transitively add Baubles, so we replace it @@ -49,7 +49,7 @@ project.getConfigurations() final DependencySubstitutions ds = c.getResolutionStrategy() .getDependencySubstitution() ds.substitute(ds.module("com.github.GTNewHorizons:Baubles")) - .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.2.4-GTNH")) + .using(ds.module("com.github.GTNewHorizons:Baubles-Expanded:2.2.6-GTNH")) .withClassifier("dev") .because("Baubles-Expanded replaces Baubles") }) diff --git a/gradle.properties b/gradle.properties index 1ad7da2..1f70658 100644 --- a/gradle.properties +++ b/gradle.properties @@ -43,6 +43,10 @@ developmentEnvironmentUserName = Developer # See https://github.com/bsideup/jabel for details on how this works. enableModernJavaSyntax = true +# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues, +# and should *not* be used in most situations. -1 disables this. +# forceToolchainVersion = -1 + # Enables injecting missing generics into the decompiled source code for a better coding experience. # Turns most publicly visible List, Map, etc. into proper List, Map types. enableGenericInjection = true @@ -200,3 +204,6 @@ curseForgeRelations = # This is meant to be set in $HOME/.gradle/gradle.properties. # ideaCheckSpotlessOnBuild = true +# Non-GTNH properties +org.gradle.configuration-cache = true +org.gradle.parallel = true diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties new file mode 100644 index 0000000..b30b550 --- /dev/null +++ b/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,12 @@ +#This file is generated by updateDaemonJvm +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/b41931cf1e70bc8e08d7dd19c343ef00/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/b41931cf1e70bc8e08d7dd19c343ef00/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/46949723aaa20c7b64d7ecfed7207034/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/d6690dfd71c4c91e08577437b5b2beb0/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/b41931cf1e70bc8e08d7dd19c343ef00/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/3cd7045fca9a72cd9bc7d14a385e594c/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/552c7bffe0370c66410a51c55985b511/redirect +toolchainVersion=25 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55baabb587c669f562ae36f953de2481846..f8e1ee3125fe0768e9a76ee977ac089eb657005e 100644 GIT binary patch delta 37442 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

WNp5~7YD4``2J+2^JLXSDAn1#GQa=Wm~d2R({ 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 delta 35599 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 ORzXA2f%7X@nSTIfr%7r6 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d4081da..23449a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a9..adff685 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index db3a6ac..c4bdd3a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle.kts b/settings.gradle.kts index 1cd4b02..7239a9e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,5 +17,5 @@ pluginManagement { } plugins { - id("com.gtnewhorizons.gtnhsettingsconvention") version("1.0.48") + id("com.gtnewhorizons.gtnhsettingsconvention") version("2.0.7") } From 98ec8044cecb02e65b4fc884faa0d510a7537c7d Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 9 Jan 2026 00:37:51 +0800 Subject: [PATCH 139/160] Fix potential NPE crash from bad trade request with invalid tradegroup. --- .../java/com/cubefury/vendingmachine/trade/TradeManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 568c735..e5368f9 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -183,6 +183,9 @@ public void setTradeState(@Nonnull UUID player, TradeGroup tg, TradeHistory hist } public boolean canExecuteTrade(@Nonnull UUID player, TradeGroup tg) { + if (tg == null) { + return false; + } long currentTimestamp = System.currentTimeMillis(); TradeHistory history = getTradeState(player, tg); long lastTradeTime = history.lastTrade; From ffb2b6603cff19c0490e7ad78a683c67fbfce3c4 Mon Sep 17 00:00:00 2001 From: "Nikolay S." Date: Sat, 10 Jan 2026 05:09:10 -0600 Subject: [PATCH 140/160] Registry Name Migration for NewHorizonsCoreMod --- .../vendingmachine/trade/CurrencyType.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java index 8851367..0df3212 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java @@ -9,20 +9,20 @@ public enum CurrencyType { - ADVENTURE("adventure", "dreamcraft:item.CoinAdventure", "gui/icons/itemCoinAdventure.png"), - BEES("bees", "dreamcraft:item.CoinBees", "gui/icons/itemCoinBees.png"), - BLOOD("blood", "dreamcraft:item.CoinBlood", "gui/icons/itemCoinBlood.png"), - CHEMIST("chemist", "dreamcraft:item.CoinChemist", "gui/icons/itemCoinChemist.png"), - COOK("cook", "dreamcraft:item.CoinCook", "gui/icons/itemCoinCook.png"), - DARK_WIZARD("darkWizard", "dreamcraft:item.CoinDarkWizard", "gui/icons/itemCoinDarkWizard.png"), - FARMER("farmer", "dreamcraft:item.CoinFarmer", "gui/icons/itemCoinFarmer.png"), - FLOWER("flower", "dreamcraft:item.CoinFlower", "gui/icons/itemCoinFlower.png"), - FORESTRY("forestry", "dreamcraft:item.CoinForestry", "gui/icons/itemCoinForestry.png"), - SMITH("smith", "dreamcraft:item.CoinSmith", "gui/icons/itemCoinSmith.png"), - SPACE("space", "dreamcraft:item.CoinSpace", "gui/icons/itemCoinSpace.png"), - SURVIVOR("survivor", "dreamcraft:item.CoinSurvivor", "gui/icons/itemCoinSurvivor.png"), - TECHNICIAN("technician", "dreamcraft:item.CoinTechnician", "gui/icons/itemCoinTechnician.png"), - WITCH("witch", "dreamcraft:item.CoinWitch", "gui/icons/itemCoinWitch.png"), + ADVENTURE("adventure", "dreamcraft:CoinAdventure", "gui/icons/itemCoinAdventure.png"), + BEES("bees", "dreamcraft:CoinBees", "gui/icons/itemCoinBees.png"), + BLOOD("blood", "dreamcraft:CoinBlood", "gui/icons/itemCoinBlood.png"), + CHEMIST("chemist", "dreamcraft:CoinChemist", "gui/icons/itemCoinChemist.png"), + COOK("cook", "dreamcraft:CoinCook", "gui/icons/itemCoinCook.png"), + DARK_WIZARD("darkWizard", "dreamcraft:CoinDarkWizard", "gui/icons/itemCoinDarkWizard.png"), + FARMER("farmer", "dreamcraft:CoinFarmer", "gui/icons/itemCoinFarmer.png"), + FLOWER("flower", "dreamcraft:CoinFlower", "gui/icons/itemCoinFlower.png"), + FORESTRY("forestry", "dreamcraft:CoinForestry", "gui/icons/itemCoinForestry.png"), + SMITH("smith", "dreamcraft:CoinSmith", "gui/icons/itemCoinSmith.png"), + SPACE("space", "dreamcraft:CoinSpace", "gui/icons/itemCoinSpace.png"), + SURVIVOR("survivor", "dreamcraft:CoinSurvivor", "gui/icons/itemCoinSurvivor.png"), + TECHNICIAN("technician", "dreamcraft:CoinTechnician", "gui/icons/itemCoinTechnician.png"), + WITCH("witch", "dreamcraft:CoinWitch", "gui/icons/itemCoinWitch.png"), // comment before semicolon to reduce merge conflicts ; From 46a87b31d9221228a28873686f6622c721eda545 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 21 Jan 2026 18:55:17 +0800 Subject: [PATCH 141/160] Add hot db reload --- .../command/CommandVending.java | 2 + .../command/vending/SubCmdAdd.java | 1 - .../command/vending/SubCmdReload.java | 50 +++++++++++++++++++ .../handlers/SaveLoadHandler.java | 9 ++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index bf7b78d..0652d86 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; +import com.cubefury.vendingmachine.command.vending.SubCmdReload; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; import net.minecraft.util.ChatComponentText; @@ -22,6 +23,7 @@ public class CommandVending extends CommandBase { register(new SubCmdAdd()); register(new SubCmdSet()); register(new SubCmdReset()); + register(new SubCmdReload()); } private static void register(IVendingSubcommand cmd) { diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java index ce3f3fd..22b774c 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java @@ -36,7 +36,6 @@ public void execute(ICommandSender sender, String[] args) throws CommandExceptio boolean allCurrency = false; CurrencyType type = null; int amount = 0; - VendingMachine.LOG.info(args.length); switch (args.length) { case 2: { diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java new file mode 100644 index 0000000..fadfa0b --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java @@ -0,0 +1,50 @@ +package com.cubefury.vendingmachine.command.vending; + +import com.cubefury.vendingmachine.handlers.SaveLoadHandler; +import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.ChatComponentText; + +import java.util.Collections; +import java.util.List; + +public class SubCmdReload implements IVendingSubcommand { + + @Override + public String getName() { + return "reload"; + } + + @Override + public String getUsage(ICommandSender sender) { + return "/vending reload database"; + } + + @Override + public void execute(ICommandSender sender, String[] args) throws CommandException { + if (args.length != 1) { + sender.addChatMessage(new ChatComponentText("Usage: " + getUsage(sender))); + return; + } + + SaveLoadHandler.INSTANCE.reloadDatabase(); + NetTradeDbSync.sendDatabase(null, false); + + sender.addChatMessage(new ChatComponentText("Reloaded Trade Database")); + } + + @Override + public List tabComplete(ICommandSender sender, String[] args) { + switch (args.length) { + case 0: { + return CommandBase + .getListOfStringsFromIterableMatchingLastWord(args, Collections.singletonList("database")); + } + default: { + return null; + } + } + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 9678b38..03f0cd7 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -12,6 +12,7 @@ import java.util.concurrent.Future; import java.util.stream.Collectors; +import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.server.MinecraftServer; @@ -131,4 +132,12 @@ public void unloadAll() { TradeManager.INSTANCE.clearTradeState(null); } + public void reloadDatabase() { + TradeDatabase.INSTANCE.clear(); + TradeManager.INSTANCE.clearTradeState(null); + + loadDatabase(); + loadTradeState(); + } + } From cde6546ff306c9c90834d14b03d2c7d1a733daa7 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 1 Feb 2026 14:15:31 +0800 Subject: [PATCH 142/160] spotless --- .../cubefury/vendingmachine/command/CommandVending.java | 2 +- .../vendingmachine/command/vending/SubCmdAdd.java | 1 - .../vendingmachine/command/vending/SubCmdReload.java | 9 +++++---- .../vendingmachine/handlers/SaveLoadHandler.java | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java index 0652d86..11ce899 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java +++ b/src/main/java/com/cubefury/vendingmachine/command/CommandVending.java @@ -5,13 +5,13 @@ import java.util.List; import java.util.Map; -import com.cubefury.vendingmachine.command.vending.SubCmdReload; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommandSender; import net.minecraft.util.ChatComponentText; import com.cubefury.vendingmachine.command.vending.IVendingSubcommand; import com.cubefury.vendingmachine.command.vending.SubCmdAdd; +import com.cubefury.vendingmachine.command.vending.SubCmdReload; import com.cubefury.vendingmachine.command.vending.SubCmdReset; import com.cubefury.vendingmachine.command.vending.SubCmdSet; diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java index 22b774c..6d6d718 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdAdd.java @@ -12,7 +12,6 @@ import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.ChatComponentText; -import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.command.Utils; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyType; diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java index fadfa0b..47b625a 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java @@ -1,14 +1,15 @@ package com.cubefury.vendingmachine.command.vending; -import com.cubefury.vendingmachine.handlers.SaveLoadHandler; -import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; +import java.util.Collections; +import java.util.List; + import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; import net.minecraft.util.ChatComponentText; -import java.util.Collections; -import java.util.List; +import com.cubefury.vendingmachine.handlers.SaveLoadHandler; +import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; public class SubCmdReload implements IVendingSubcommand { diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 03f0cd7..8f4542d 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -12,7 +12,6 @@ import java.util.concurrent.Future; import java.util.stream.Collectors; -import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.server.MinecraftServer; From 9c95a7e67b8dba1e486cdc3c15d41aee75c76b90 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 1 Feb 2026 14:40:17 +0800 Subject: [PATCH 143/160] fix crash when opening UI after reload. --- .../java/com/cubefury/vendingmachine/trade/TradeManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index e5368f9..84cf5cf 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -168,6 +168,11 @@ public void clearTradeState(@Nullable UUID player) { tradeGroupStates.forEach((uuid, tgs) -> tgs.clearTradeState(player)); clearCurrency(player); clearNotificationQueue(player); + if (player == null) { + availableTrades.clear(); + } else { + availableTrades.remove(player); + } } public TradeHistory getTradeState(@Nonnull UUID player, TradeGroup tg) { From ed7ecc569255374b7aa44b05148bcbc11af0a527 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sun, 1 Feb 2026 15:24:56 +0800 Subject: [PATCH 144/160] Fix command behaviour. --- .../cubefury/vendingmachine/command/vending/SubCmdReload.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java index 47b625a..b1abf61 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java @@ -25,7 +25,7 @@ public String getUsage(ICommandSender sender) { @Override public void execute(ICommandSender sender, String[] args) throws CommandException { - if (args.length != 1) { + if (args.length != 1 || args[0].compareTo("database") != 0) { sender.addChatMessage(new ChatComponentText("Usage: " + getUsage(sender))); return; } @@ -39,7 +39,7 @@ public void execute(ICommandSender sender, String[] args) throws CommandExceptio @Override public List tabComplete(ICommandSender sender, String[] args) { switch (args.length) { - case 0: { + case 1: { return CommandBase .getListOfStringsFromIterableMatchingLastWord(args, Collections.singletonList("database")); } From 007903458cf8661c9b0b1872ee0fd58ce639dc59 Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 4 Feb 2026 01:33:51 +0800 Subject: [PATCH 145/160] Update readme (#59) --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b236278..82150fa 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,16 @@ This mod adds a vending machine, unlocking trades based on questbook data. If yo ### Command -**Note: All commands require OP to run** +**Note: All commands require OP to run**. + +If your command still refuses to run, ensure your OP permission level in server.properties is set to 4. |Task| Command | |--|---------------------------------------------------| |**Set coin**| `/vending set [player] ` | |**Add coin**| `/vending add [player] ` | -|**Reset coins**| `/vending reset [player] ` +|**Reset coins**| `/vending reset [player] ` | +|**Reload database** | `/vending reload database` | ## Current Status From 1c0ada399df4f6e22a6c21e38f88373a76374b7e Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 5 Feb 2026 00:59:57 +0800 Subject: [PATCH 146/160] Add structure error (#61) * Add incomplete structure message * Remove trades if incomplete structure. --- .../blocks/gui/MTEVendingMachineGui.java | 14 ++++++++++++++ .../assets/vendingmachine/lang/en_US.lang | 1 + 2 files changed, 15 insertions(+) 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 c568217..54a3ead 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -30,6 +30,7 @@ import com.cleanroommc.modularui.widgets.ListWidget; import com.cleanroommc.modularui.widgets.PagedWidget; import com.cleanroommc.modularui.widgets.SlotGroupWidget; +import com.cleanroommc.modularui.widgets.TextWidget; import com.cleanroommc.modularui.widgets.ToggleButton; import com.cleanroommc.modularui.widgets.layout.Column; import com.cleanroommc.modularui.widgets.layout.Flow; @@ -500,6 +501,13 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t .collapseDisabledChild(true); tradeList.child(new Row().height(2)); + + // Incomplete Structure status message + Flow statusRow = new Row().height(10).width(TRADE_ROW_WIDTH).marginLeft(2) + .child(new TextWidget(IKey.lang("vendingmachine.gui.error.incomplete_structure"))) + .setEnabledIf(slot -> !this.getBase().getActive()); + tradeList.child(statusRow); + // Higher first row top margin Flow row = new TradeRow().height(TILE_ITEM_HEIGHT +2).width(TRADE_ROW_WIDTH).marginLeft(2); @@ -518,6 +526,9 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t }) .tooltipAutoUpdate(true) .setEnabledIf(slot -> { + if (!this.getBase().getActive()) { + return false; + } TradeItemDisplayWidget display = ((TradeItemDisplayWidget) slot); return VMConfig.gui.display_type == display.displayType && display.getDisplay() != null; }) @@ -548,6 +559,9 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t }) .tooltipAutoUpdate(true) .setEnabledIf(slot -> { + if (!this.getBase().getActive()) { + return false; + } TradeItemDisplayWidget display = ((TradeItemDisplayWidget) slot); return VMConfig.gui.display_type == display.displayType && display.getDisplay() != null; })); diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 78d5675..59514d8 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -32,6 +32,7 @@ vendingmachine.gui.cooldown_display.minute=m vendingmachine.gui.cooldown_display.hour=h vendingmachine.gui.cooldown_display.day=d +vendingmachine.gui.error.incomplete_structure=Incomplete Structure. vendingmachine.gui.error.player_using=Someone is using the vending machine at the moment. vendingmachine.chat.trade_restock=Vending Machine Restocked: %s From de8809d02451fdcd4cd82c0ad998e27570f9c331 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Fri, 6 Feb 2026 22:56:28 +0100 Subject: [PATCH 147/160] update --- dependencies.gradle | 12 ++++++------ gradle.properties | 26 +++++++++++++++++++++++--- settings.gradle.kts | 2 +- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 1d3aa0e..0b2a695 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -34,13 +34,13 @@ * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { - implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.48-GTNH:dev") - implementation("com.github.GTNewHorizons:GTNHLib:0.8.41:dev") - compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.14-GTNH:dev") + implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.60-GTNH:dev") + implementation("com.github.GTNewHorizons:GTNHLib:0.9.10:dev") + compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.26-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.24-1.7.10:dev") - implementation("com.github.GTNewHorizons:StructureLib:1.4.25:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.179:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.35-1.7.10:dev") + implementation("com.github.GTNewHorizons:StructureLib:1.4.28:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.258:dev") } // deps may transitively add Baubles, so we replace it diff --git a/gradle.properties b/gradle.properties index 1f70658..5eee7b3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,14 +39,34 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co # `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE. developmentEnvironmentUserName = Developer -# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8. -# See https://github.com/bsideup/jabel for details on how this works. -enableModernJavaSyntax = true +# Enables modern Java syntax support. Valid values: +# - false: No modern syntax, Java 8 only +# - jabel: Jabel syntax-only support, compiles to J8 bytecode +# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs) +# - modern: Native modern Java bytecode, no downgrading +enableModernJavaSyntax = jabel # If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues, # and should *not* be used in most situations. -1 disables this. # forceToolchainVersion = -1 +# Target JVM version for JVM Downgrader bytecode downgrading. +# Only used when enableModernJavaSyntax = jvmDowngrader +# downgradeTargetVersion = 8 + +# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only). +# Classes will be available in META-INF/versions/N/ for each version N in this list. +# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade). +# jvmDowngraderMultiReleaseVersions = 21,25 + +# Specifies how JVM Downgrader API stubs are provided. Options: +# - shade: Shade minimized stubs into the jar +# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint) +# - external: Another dependency provides stubs (no constraint, no warning) +# - (empty): Warning reminding you to configure stubs +# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md +# jvmDowngraderStubsProvider = + # Enables injecting missing generics into the decompiled source code for a better coding experience. # Turns most publicly visible List, Map, etc. into proper List, Map types. enableGenericInjection = true diff --git a/settings.gradle.kts b/settings.gradle.kts index 7239a9e..e5a5ba9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,5 +17,5 @@ pluginManagement { } plugins { - id("com.gtnewhorizons.gtnhsettingsconvention") version("2.0.7") + id("com.gtnewhorizons.gtnhsettingsconvention") version("2.0.19") } From cf4dac14490db3f53615d7616e28679c8c600939 Mon Sep 17 00:00:00 2001 From: Martin Robertz Date: Sat, 7 Feb 2026 01:12:00 +0100 Subject: [PATCH 148/160] fix (#62) --- .../vendingmachine/blocks/gui/MTEVendingMachineGui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 54a3ead..108158e 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -647,7 +647,7 @@ private IWidget createInventoryRow() { .bottom(5) .childIf( base.doesBindPlayerInventory(), - SlotGroupWidget.playerInventory(false) + () -> SlotGroupWidget.playerInventory(false) .marginLeft(4)); } From 47afd3082bbe720d63a0e14f3808acc2b71efcf6 Mon Sep 17 00:00:00 2001 From: chrombread <119648279+chrombread@users.noreply.github.com> Date: Sat, 7 Feb 2026 19:11:11 -0800 Subject: [PATCH 149/160] adapt to mui2 upstream (#63) --- dependencies.gradle | 4 ++-- .../blocks/gui/TradeItemDisplayWidget.java | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 0b2a695..cc3ba00 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,9 +38,9 @@ dependencies { implementation("com.github.GTNewHorizons:GTNHLib:0.9.10:dev") compileOnly("com.github.GTNewHorizons:BetterQuesting:3.8.26-GTNH:dev") - implementation("com.github.GTNewHorizons:ModularUI2:2.3.35-1.7.10:dev") + implementation("com.github.GTNewHorizons:ModularUI2:2.3.39-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.28:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.258:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.266:dev") } // deps may transitively add Baubles, so we replace it diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index f8da553..8cc6839 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull; import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.api.value.ISyncOrValue; import com.cleanroommc.modularui.api.value.IValue; import com.cleanroommc.modularui.api.widget.Interactable; import com.cleanroommc.modularui.drawable.DynamicDrawable; @@ -12,8 +13,7 @@ import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; import com.cleanroommc.modularui.theme.WidgetThemeEntry; import com.cleanroommc.modularui.utils.Platform; -import com.cleanroommc.modularui.value.sync.GenericSyncValue; -import com.cleanroommc.modularui.value.sync.SyncHandler; +import com.cleanroommc.modularui.value.ObjectValue; import com.cleanroommc.modularui.widgets.ItemDisplayWidget; import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.gui.GuiTextures; @@ -83,7 +83,7 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { GuiDraw.drawText(" " + this.display.display.stackSize, 4, 9, 1.0f, textColor, false); GuiDraw.drawItem(item, 26, 4, 16, 16, context.getCurrentDrawingZ()); if (this.display.tradeableNow) { - GuiDraw.drawOutline(1, 1, 45, 23, 0x883CFF00, 2); + GuiDraw.drawBorderInsideLTRB(1, 1, 45, 23, 2, 0x883CFF00); } if (!this.checkVmActive() || this.display.hasCooldown || !this.display.enabled) { GuiDraw.drawRoundedRect( @@ -135,17 +135,18 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { } @Override - public boolean isValidSyncHandler(SyncHandler syncHandler) { - if (syncHandler instanceof GenericSyncValuegenericSyncValue && genericSyncValue.isOfType(ItemStack.class)) { - this.value = genericSyncValue.cast(); + public boolean isValidSyncOrValue(@NotNull ISyncOrValue syncOrValue) { + if (syncOrValue instanceof ObjectValuesyncValue && syncValue.isValueOfType(ItemStack.class)) { + this.value = syncValue.castValueNullable(ItemStack.class); return true; + } return false; } public ItemDisplayWidget item(IValue itemSupplier) { this.value = itemSupplier; - setValue(itemSupplier); + setSyncOrValue(itemSupplier); return this; } From aa3633ef8bd1cb40a61c25f31399053987781cb4 Mon Sep 17 00:00:00 2001 From: UltraProdigy <187078471+UltraProdigy@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:27:38 -0500 Subject: [PATCH 150/160] Show Structure Incomplete When Structure is Incomplete (#65) * fix * fix for the fix --- .../blocks/MTEVendingMachine.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 3eccf42..eeddf83 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -116,8 +116,8 @@ public class MTEVendingMachine extends MTEMultiBlockBase private MultiblockTooltipBuilder tooltipBuilder; public int mUpdate = 0; - public boolean mMachine = false; - private boolean mIsAnimated; + + private final boolean mIsAnimated; public ItemStackHandler inputItems = new ItemStackHandler(INPUT_SLOTS); public ItemStackHandler outputItems = new ItemStackHandler(OUTPUT_SLOTS); @@ -609,20 +609,20 @@ public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack a @Override public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { - if (aBaseMetaTileEntity.isClientSide() && !aBaseMetaTileEntity.isActive()) { - OverlayHelper.clearVMOverlay(overlayTickets); - } - if (aBaseMetaTileEntity.isServerSide()) { - dispenseItems(); - if ( - this.getActive() && this.ticksSinceTradeUpdate++ >= VMConfig.vendingMachineSettings.gui_refresh_interval - ) { - this.sendTradeUpdate(); - } - if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { - this.mMachine = checkMachine(aBaseMetaTileEntity, null); - aBaseMetaTileEntity.setActive(this.mMachine); + super.onPostTick(aBaseMetaTileEntity, aTimer); + if (aBaseMetaTileEntity.isClientSide()) { + if (!aBaseMetaTileEntity.isActive()) { + OverlayHelper.clearVMOverlay(overlayTickets); } + return; + } else if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { + this.mMachine = checkMachine(aBaseMetaTileEntity, null); + } + aBaseMetaTileEntity.setActive(this.mMachine); + if (!this.mMachine) return; + dispenseItems(); + if (this.ticksSinceTradeUpdate++ >= VMConfig.vendingMachineSettings.gui_refresh_interval) { + this.sendTradeUpdate(); } } From 5ce5f5318596da7636e88bb2d96bcd33cb715503 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 12 Feb 2026 00:14:37 +0800 Subject: [PATCH 151/160] Added trade state reload command (#64) --- README.md | 1 + .../command/vending/SubCmdReload.java | 39 ++++++++++++++----- .../handlers/SaveLoadHandler.java | 24 ++++++++++-- .../vendingmachine/trade/TradeManager.java | 4 +- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 82150fa..32a041b 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ If your command still refuses to run, ensure your OP permission level in server. |**Add coin**| `/vending add [player] ` | |**Reset coins**| `/vending reset [player] ` | |**Reload database** | `/vending reload database` | +|**Reload trade state**| `/vending reload tradestate [player]` | ## Current Status diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java index b1abf61..034221e 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java @@ -1,7 +1,8 @@ package com.cubefury.vendingmachine.command.vending; -import java.util.Collections; +import java.util.Arrays; import java.util.List; +import java.util.UUID; import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; @@ -10,6 +11,8 @@ import com.cubefury.vendingmachine.handlers.SaveLoadHandler; import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.TradeManager; public class SubCmdReload implements IVendingSubcommand { @@ -20,20 +23,31 @@ public String getName() { @Override public String getUsage(ICommandSender sender) { - return "/vending reload database"; + return "/vending reload database, /vending reload tradestate [player]"; } @Override public void execute(ICommandSender sender, String[] args) throws CommandException { - if (args.length != 1 || args[0].compareTo("database") != 0) { + if (args.length == 1 && args[0].equals("database")) { + SaveLoadHandler.INSTANCE.reloadDatabase(); + NetTradeDbSync.sendDatabase(null, false); + + sender.addChatMessage(new ChatComponentText("Reloaded Trade Database")); + } else if ((args.length == 1 || args.length == 2) && args[0].equals("tradestate")) { + UUID target = args.length == 1 + ? NameCache.INSTANCE.getUUIDFromPlayer(CommandBase.getCommandSenderAsPlayer(sender)) + : NameCache.INSTANCE.getUUID(args[1]); + if (target == null) { + sender.addChatMessage(new ChatComponentText("Could not resolve UUID of player.")); + return; + } + TradeManager.INSTANCE.clearTradeState(target); + SaveLoadHandler.INSTANCE.loadTradeState(target); + sender.addChatMessage( + new ChatComponentText("Reloaded trade state for " + NameCache.INSTANCE.getName(target))); + } else { sender.addChatMessage(new ChatComponentText("Usage: " + getUsage(sender))); - return; } - - SaveLoadHandler.INSTANCE.reloadDatabase(); - NetTradeDbSync.sendDatabase(null, false); - - sender.addChatMessage(new ChatComponentText("Reloaded Trade Database")); } @Override @@ -41,7 +55,12 @@ public List tabComplete(ICommandSender sender, String[] args) { switch (args.length) { case 1: { return CommandBase - .getListOfStringsFromIterableMatchingLastWord(args, Collections.singletonList("database")); + .getListOfStringsFromIterableMatchingLastWord(args, Arrays.asList("database", "tradestate")); + } + case 2: { + return args[0].equals("tradestate") + ? CommandBase.getListOfStringsFromIterableMatchingLastWord(args, NameCache.INSTANCE.getAllNames()) + : null; } default: { return null; diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 8f4542d..7a3a6b7 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -12,6 +12,8 @@ import java.util.concurrent.Future; import java.util.stream.Collectors; +import javax.annotation.Nullable; + import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.server.MinecraftServer; @@ -53,7 +55,7 @@ public void init(MinecraftServer server) { unloadAll(); loadDatabase(); - loadTradeState(); + loadTradeState(null); loadNames(); } @@ -83,8 +85,13 @@ public Future writeDatabase() { out -> NBTConverter.NBTtoJSON_Compound(TradeDatabase.INSTANCE.writeToNBT(new NBTTagCompound()), out, true)); } - public void loadTradeState() { - if (dirTradeState.exists()) { + public void loadTradeState(@Nullable UUID player) { + if (!dirTradeState.exists()) { + JsonHelper.populateTradeStateFromFiles(Collections.emptyList()); + return; + } + + if (player == null) { File[] fileList = dirTradeState.listFiles(); if (fileList != null) { @@ -97,6 +104,15 @@ public void loadTradeState() { } else { JsonHelper.populateTradeStateFromFiles(Collections.emptyList()); } + return; + } + + File playerFile = new File(dirTradeState, player + ".json"); + + if (playerFile.exists() && playerFile.isFile()) { + JsonHelper.populateTradeStateFromFiles(Collections.singletonList(playerFile)); + } else { + JsonHelper.populateTradeStateFromFiles(Collections.emptyList()); } } @@ -136,7 +152,7 @@ public void reloadDatabase() { TradeManager.INSTANCE.clearTradeState(null); loadDatabase(); - loadTradeState(); + loadTradeState(null); } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index 84cf5cf..18f4ee5 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java @@ -93,7 +93,7 @@ public void removeSatisfiedCondition(TradeGroup tradeGroup, @Nullable UUID playe } } - private void updateAvailableTrades(UUID tradeGroupId, @Nullable UUID player) { + private void updateAvailableTrades(UUID tradeGroupId, @Nonnull UUID player) { if ( tradeGroupStates.get(tradeGroupId) .satisfiesTrade(player) @@ -219,7 +219,7 @@ public void executeTrade(@Nonnull UUID player, TradeGroup tg) { } } - public void populateTradeStateFromNBT(NBTTagCompound nbt, UUID player, boolean merge) { + public void populateTradeStateFromNBT(NBTTagCompound nbt, @Nonnull UUID player, boolean merge) { NBTTagList tradeStateList = nbt.getTagList("tradeState", Constants.NBT.TAG_COMPOUND); if (!merge) { clearTradeState(player); From e42ccfa9e961a556b9fbe5b15af40addafc795e2 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 13 Feb 2026 23:51:46 +0800 Subject: [PATCH 152/160] Check if player is not accessing vending machine before reloading tradestate (#66) * Check if player is not accessing vending machine before allowing trade state reload. * Grammar is hard --- .../command/vending/SubCmdReload.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java index 034221e..51d1ba8 100644 --- a/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java +++ b/src/main/java/com/cubefury/vendingmachine/command/vending/SubCmdReload.java @@ -7,13 +7,20 @@ import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.ChatComponentText; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularContainer; +import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.handlers.SaveLoadHandler; import com.cubefury.vendingmachine.network.handlers.NetTradeDbSync; import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.TradeManager; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + public class SubCmdReload implements IVendingSubcommand { @Override @@ -41,6 +48,22 @@ public void execute(ICommandSender sender, String[] args) throws CommandExceptio sender.addChatMessage(new ChatComponentText("Could not resolve UUID of player.")); return; } + MinecraftServer server = MinecraftServer.getServer(); + if (server != null) { + EntityPlayerMP player = server.getConfigurationManager() + .func_152612_a(NameCache.INSTANCE.getName(target)); + if ( + player != null && player.openContainer instanceof ModularContainer container + && container.getGuiData() instanceof PosGuiData guiData + && guiData.getTileEntity() instanceof IGregTechTileEntity gte + && gte.getMetaTileEntity() instanceof MTEVendingMachine + ) { + sender.addChatMessage( + new ChatComponentText( + "Cannot reload trade state for a player currently accessing a vending machine.")); + return; + } + } TradeManager.INSTANCE.clearTradeState(target); SaveLoadHandler.INSTANCE.loadTradeState(target); sender.addChatMessage( From b89d2355bfe75a84cc7cb6b77bfd22c7530e6caa Mon Sep 17 00:00:00 2001 From: cubefury Date: Wed, 4 Mar 2026 13:00:42 +0800 Subject: [PATCH 153/160] Fix item ejecting direction (#67) --- .../blocks/MTEVendingMachine.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index eeddf83..3c9979b 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -815,22 +815,19 @@ public void spawnItem(ItemStack stack) { .getYCoord(); int posZ = this.getBaseMetaTileEntity() .getZCoord(); - int offsetX = this.getExtendedFacing() - .getDirection().offsetX; - int offsetY = this.getExtendedFacing() - .getDirection().offsetY; - int offsetZ = this.getExtendedFacing() - .getDirection().offsetZ; + + ForgeDirection frontFacing = this.getBaseMetaTileEntity() + .getFrontFacing(); final EntityItem itemEntity = new EntityItem( world, - posX + offsetX * 0.5, - posY + offsetY * 0.5, - posZ + offsetZ * 0.5, + posX + 0.5 + frontFacing.offsetX * 0.7, + posY + 0.5 + frontFacing.offsetY * 0.7, + posZ + 0.5 + frontFacing.offsetZ * 0.7, stack); itemEntity.delayBeforeCanPickup = 0; - itemEntity.motionX = 0.05f * offsetX; - itemEntity.motionY = 0.05f * offsetY; - itemEntity.motionZ = 0.05f * offsetZ; + itemEntity.motionX = 0.1f * frontFacing.offsetX; + itemEntity.motionY = 0.1f * frontFacing.offsetY; + itemEntity.motionZ = 0.1f * frontFacing.offsetZ; world.spawnEntityInWorld(itemEntity); } From 83c4f3ce349c890e4a017efe55fc5f96857618f7 Mon Sep 17 00:00:00 2001 From: cubefury Date: Thu, 12 Mar 2026 02:38:48 +0800 Subject: [PATCH 154/160] Favourites tab (#68) * swap out deprecated method * Remove unnecessary logic from coin eject buttons * Add favourites feature * Added saveload logic for favourites. * Add favourite toggle hint * Reset view to all items when favourites tab is empty * Fix serverside crash * spotless * Push favourited trades to the top in smart compare sort mode * Increased margins for tile display to stop console spam * spotless * Add placeholder icons * Remove unnecessary comments * Remove pair util class * Add favourites priority in both sort modes. * Removed delay between when ctrl released and tab switching when favourites are emptied. * Added preemptive favourites clearing when attemping to load from file, in case directory goes missing somehow when switching worlds * remove unnecessary pendingworldinit variable * Address comments * sanitize filenames to remove illegal characters --- .../cubefury/vendingmachine/ClientProxy.java | 8 + .../vendingmachine/blocks/gui/CoinButton.java | 13 +- .../blocks/gui/MTEVendingMachineGui.java | 37 ++++- .../blocks/gui/TradeItemDisplay.java | 2 + .../blocks/gui/TradeItemDisplayWidget.java | 16 ++ .../blocks/gui/TradeMainPanel.java | 41 +++++- .../vendingmachine/gui/GuiTextures.java | 8 + .../handlers/ClientEventHandler.java | 37 +++++ .../handlers/SaveLoadHandler.java | 43 ++++++ .../trade/FavouritesTracker.java | 138 ++++++++++++++++++ .../vendingmachine/trade/TradeCategory.java | 1 + .../vendingmachine/util/JsonHelper.java | 7 + .../assets/vendingmachine/lang/en_US.lang | 2 + .../gui/icons/favourite_indicator.png | Bin 0 -> 298 bytes .../textures/gui/icons/favourites.png | Bin 0 -> 1227 bytes 15 files changed, 335 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/cubefury/vendingmachine/handlers/ClientEventHandler.java create mode 100644 src/main/java/com/cubefury/vendingmachine/trade/FavouritesTracker.java create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/icons/favourite_indicator.png create mode 100644 src/main/resources/assets/vendingmachine/textures/gui/icons/favourites.png diff --git a/src/main/java/com/cubefury/vendingmachine/ClientProxy.java b/src/main/java/com/cubefury/vendingmachine/ClientProxy.java index a64f4a3..8434acc 100644 --- a/src/main/java/com/cubefury/vendingmachine/ClientProxy.java +++ b/src/main/java/com/cubefury/vendingmachine/ClientProxy.java @@ -2,8 +2,11 @@ import net.minecraftforge.common.MinecraftForge; +import com.cubefury.vendingmachine.handlers.ClientEventHandler; +import com.cubefury.vendingmachine.handlers.SaveLoadHandler; import com.cubefury.vendingmachine.integration.nei.NEIConfig; +import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; @@ -20,6 +23,7 @@ public void preInit(FMLPreInitializationEvent event) { public void init(FMLInitializationEvent event) { MinecraftForge.EVENT_BUS.register(new NEIConfig()); super.init(event); + SaveLoadHandler.INSTANCE.clientInit(); } public boolean isClient() { @@ -29,6 +33,10 @@ public boolean isClient() { @Override public void registerHandlers() { super.registerHandlers(); + MinecraftForge.EVENT_BUS.register(ClientEventHandler.INSTANCE); + FMLCommonHandler.instance() + .bus() + .register(ClientEventHandler.INSTANCE); } } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java index b8d52f1..e1610e6 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/CoinButton.java @@ -26,15 +26,10 @@ public CoinButton(TradeMainPanel panel, CurrencyType type) { if (!panel.shiftHeld) { return Result.IGNORE; } - switch (mouseButton) { - case 0: - next(); - Interactable.playButtonClickSound(); - return Result.SUCCESS; - case 1: - prev(); - Interactable.playButtonClickSound(); - return Result.SUCCESS; + if (mouseButton == 0) { + next(); + Interactable.playButtonClickSound(); + return Result.SUCCESS; } return Result.IGNORE; } 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 108158e..4f3e5fb 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -46,6 +46,7 @@ import com.cubefury.vendingmachine.storage.NameCache; import com.cubefury.vendingmachine.trade.CurrencyItem; import com.cubefury.vendingmachine.trade.CurrencyType; +import com.cubefury.vendingmachine.trade.FavouritesTracker; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeManager; @@ -73,6 +74,7 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { private PosGuiData guiData; private final PagedWidget.Controller tabController; + public IWidget favouritesTabWidget; private final SearchBar searchBar; public static String lastSearch = ""; @@ -100,6 +102,7 @@ public MTEVendingMachineGui(MTEVendingMachine base) { ejectSingleCoin.put(type, false); } + this.tradeCategories.add(TradeCategory.FAVOURITES); this.tradeCategories.add(TradeCategory.ALL); this.tradeCategories.addAll(TradeDatabase.INSTANCE.getTradeCategories()); @@ -136,6 +139,11 @@ public ModularPanel build(PosGuiData guiData, PanelSyncManager syncManager, UISe ModularPanel panel = new TradeMainPanel("MTEMultiBlockBase", this, guiData, syncManager) .size(178, CUSTOM_UI_HEIGHT) .padding(4); + panel.onCloseAction(() -> { + if (VendingMachine.proxy.isClient()) { + FavouritesTracker.INSTANCE.saveFavourites(); + } + }); panel.child(createCategoryTabs(this.tabController)); Flow mainColumn = new Column().width(170); if (VendingMachine.proxy.isClient()) { // client side sort and filtering @@ -213,7 +221,7 @@ public IWidget createQolButtonColumn() { public IWidget createCategoryTabs(PagedWidget.Controller tabController) { Flow tabColumn = new Column().width(40) - .height(100) + .height(300) .left(-29) .top(40) .coverChildren(); @@ -235,6 +243,13 @@ public IWidget createCategoryTabs(PagedWidget.Controller tabController) { this.tradeCategories.get(index) .getUnlocalized_name())); })); + + if (tradeCategories.get(i) == TradeCategory.FAVOURITES) { + favouritesTabWidget = tabColumn.getChildren() + .get( + tabColumn.getChildren() + .size() - 1); + } } return tabColumn; } @@ -248,7 +263,7 @@ private IWidget createTitleTextStyle(String title) { .child( IKey.str(title) .asWidget() - .alignment(Alignment.Center) + .textAlign(Alignment.Center) .widgetTheme(GTWidgetThemes.TEXT_TITLE) .marginLeft(5) .marginRight(5) @@ -481,6 +496,9 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { builder.addLine( IKey.str(Translator.translate("vendingmachine.gui.trade_hint")) .style(IKey.GRAY)); + builder.addLine( + IKey.str(Translator.translate("vendingmachine.gui.favourite_hint")) + .style(IKey.GRAY)); } } @@ -509,7 +527,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t tradeList.child(statusRow); // Higher first row top margin - Flow row = new TradeRow().height(TILE_ITEM_HEIGHT +2).width(TRADE_ROW_WIDTH).marginLeft(2); + Flow row = new TradeRow().height(TILE_ITEM_HEIGHT + 4).width(TRADE_ROW_WIDTH).marginLeft(2); // Tiles Display for (int i = 0; i < MTEVendingMachine.MAX_TRADES; i++) { @@ -536,7 +554,7 @@ private IWidget createTradeUI(TradeMainPanel rootPanel, PagedWidget.Controller t if (i % TILE_ITEMS_PER_ROW == TILE_ITEMS_PER_ROW - 1) { tradeList.child(row); - row = new TradeRow().height(TILE_ITEM_HEIGHT +2).width(TRADE_ROW_WIDTH).marginLeft(2); + row = new TradeRow().height(TILE_ITEM_HEIGHT + 4).width(TRADE_ROW_WIDTH).marginLeft(2); } } if (row.hasChildren()) { @@ -733,6 +751,17 @@ private void updateTradeDisplay(Map> trade } public void updateTradeDisplay(Map> trades) { + if (favouritesTabWidget != null) { + favouritesTabWidget.setEnabled( + !trades.get(TradeCategory.FAVOURITES) + .isEmpty()); + if ( + trades.get(TradeCategory.FAVOURITES) + .isEmpty() && this.tabController.getActivePageIndex() == 0 + ) { + this.tabController.setPage(1); + } + } this.updateTradeDisplay(trades, displayedTradesTiles); this.updateTradeDisplay(trades, displayedTradesList); } diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java index 615c3ab..2ac1147 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java @@ -24,6 +24,7 @@ public class TradeItemDisplay { public boolean hasCooldown; public boolean enabled; public boolean tradeableNow; + public boolean isFavourite; public TradeItemDisplay(List fromCurrency, List fromItems, List ncItems, List toItems, ItemStack display, UUID tgID, int tradeGroupOrder, long cooldown, @@ -40,6 +41,7 @@ public TradeItemDisplay(List fromCurrency, List from this.hasCooldown = hasCooldown; this.enabled = enabled; this.tradeableNow = tradeableNow; + this.isFavourite = false; } public boolean satisfiesSearch(ItemFilter filter, String searchStringNoCase) { diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 8cc6839..f001d8e 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -18,6 +18,7 @@ import com.cubefury.vendingmachine.blocks.MTEVendingMachine; import com.cubefury.vendingmachine.gui.GuiTextures; import com.cubefury.vendingmachine.gui.WidgetThemes; +import com.cubefury.vendingmachine.trade.FavouritesTracker; import com.cubefury.vendingmachine.util.Translator; public class TradeItemDisplayWidget extends ItemDisplayWidget implements Interactable { @@ -66,11 +67,20 @@ public TradeItemDisplay getDisplay() { } public @NotNull Interactable.Result onMousePressed(int mouseButton) { + // Only do something if either shift or control is held exclusively + if (rootPanel.shiftHeld == rootPanel.ctrlHeld) { + return Result.IGNORE; + } if (rootPanel.shiftHeld) { rootPanel.attemptPurchase(this.display); pressed = true; return Result.SUCCESS; } + if (rootPanel.ctrlHeld) { + FavouritesTracker.INSTANCE.toggleFavourites(this.display.tgID, this.display.tradeGroupOrder); + rootPanel.forceGuiRefresh(); + return Result.SUCCESS; + } return Result.IGNORE; } @@ -98,6 +108,9 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { this.overlay( IKey.str(display.hasCooldown ? this.display.cooldownText : "") .style(IKey.WHITE)); + if (this.display.isFavourite) { + GuiTextures.FAVOURITE_SPRITE.draw(context, 4, 4, 6, 6, widgetTheme.getTheme()); + } } else if (this.displayType == DisplayType.LIST) { GuiDraw.drawText("" + this.display.display.stackSize, 6, 4, 0.9f, textColor, false); GuiDraw.drawItem(item, 24, 2, 9, 9, context.getCurrentDrawingZ()); @@ -130,6 +143,9 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { IKey.str(display.hasCooldown && this.display.enabled ? this.display.cooldownText : "") .style(IKey.WHITE) .scale(0.9f)); + if (this.display.isFavourite) { + GuiTextures.FAVOURITE_SPRITE.draw(context, 139, 2, 10, 10, widgetTheme.getTheme()); + } } } } 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 7d9d9e8..0c86b34 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -12,6 +12,7 @@ import net.minecraft.item.ItemStack; import org.jetbrains.annotations.NotNull; +import org.lwjgl.input.Keyboard; import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; @@ -19,6 +20,7 @@ import com.cleanroommc.modularui.value.sync.PanelSyncManager; import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.network.handlers.NetResetVMUser; +import com.cubefury.vendingmachine.trade.FavouritesTracker; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeGroup; @@ -31,6 +33,7 @@ public class TradeMainPanel extends ModularPanel { public boolean shiftHeld = false; + public boolean ctrlHeld = false; private final MTEVendingMachineGui gui; private final PanelSyncManager syncManager; private final PosGuiData guiData; @@ -47,24 +50,29 @@ public TradeMainPanel(@NotNull String name, MTEVendingMachineGui gui, PosGuiData @Override public boolean onKeyPressed(char typedChar, int keyCode) { - // left or right shift - if (keyCode == 0x2A || keyCode == 0x36) { + if (keyCode == Keyboard.KEY_LSHIFT || keyCode == Keyboard.KEY_RSHIFT) { shiftHeld = true; } + if (keyCode == Keyboard.KEY_LCONTROL || keyCode == Keyboard.KEY_RCONTROL) { + ctrlHeld = true; + } return super.onKeyPressed(typedChar, keyCode); } @Override public boolean onKeyRelease(char typedChar, int keyCode) { - // left or right shift - if (keyCode == 0x2A || keyCode == 0x36) { + if (keyCode == Keyboard.KEY_LSHIFT || keyCode == Keyboard.KEY_RSHIFT) { shiftHeld = false; } + if (keyCode == Keyboard.KEY_LCONTROL || keyCode == Keyboard.KEY_RCONTROL) { + ctrlHeld = false; + gui.setForceRefresh(); + } return super.onKeyRelease(typedChar, keyCode); } public void updateGui() { - if (shiftHeld) { + if (shiftHeld || ctrlHeld) { this.updateTradeInformation(gui.getCurrentTradeDisplayData()); } else { Map> trades = formatTrades(); @@ -74,6 +82,12 @@ public void updateGui() { private void updateTradeInformation(Map> currentData) { Map> tradeMap = new HashMap<>(); + List favouritedTrades = FavouritesTracker.INSTANCE + .filterTrades(currentData.get(TradeCategory.ALL)); + if (gui.favouritesTabWidget != null) { + gui.favouritesTabWidget.setEnabled(!favouritedTrades.isEmpty()); + } + currentData.put(TradeCategory.FAVOURITES, favouritedTrades); for (TradeItemDisplay tid : TradeManager.INSTANCE.tradeData) { tradeMap.putIfAbsent(tid.tgID, new HashMap<>()); tradeMap.get(tid.tgID) @@ -89,6 +103,7 @@ private void updateTradeInformation(Map> c tid.cooldown = cur.cooldown; tid.cooldownText = cur.cooldownText; tid.tradeableNow = cur.tradeableNow; + tid.isFavourite = FavouritesTracker.INSTANCE.isFavourite(tid); } }); } @@ -134,6 +149,7 @@ public Map> formatTrades() { if (group == null) { continue; } + tid.isFavourite = FavouritesTracker.INSTANCE.isFavourite(tid); TradeCategory category = group.getCategory(); trades.putIfAbsent(category, new ArrayList<>()); trades.get(category) @@ -160,9 +176,17 @@ public Map> formatTrades() { if (b.display.getItem() == null) return -1; if (sortMode == SortMode.ALPHABET) { + if (a.isFavourite != b.isFavourite) { + return Boolean.compare(b.isFavourite, a.isFavourite); + } return (a.display.getDisplayName() .compareTo(b.display.getDisplayName())); } else if (sortMode == SortMode.SMART) { + // favourited + if (a.isFavourite != b.isFavourite) { + return Boolean.compare(b.isFavourite, a.isFavourite); + } + // enabled or has cooldown int rankA = getRank(a); int rankB = getRank(b); @@ -191,6 +215,9 @@ public Map> formatTrades() { }); trades.replace(category, filteredTrades); } + List favouritedTrades = FavouritesTracker.INSTANCE + .filterTrades(trades.get(TradeCategory.ALL)); + trades.put(TradeCategory.FAVOURITES, favouritedTrades); return trades; } @@ -208,6 +235,10 @@ public void attemptPurchase(TradeItemDisplay display) { gui.attemptPurchase(display); } + public void forceGuiRefresh() { + gui.setForceRefresh(); + } + @Override public void dispose() { this.gui.getBase() diff --git a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java index 2a9c414..1948d19 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/GuiTextures.java @@ -130,4 +130,12 @@ public final class GuiTextures { 32, 28, 4); + + public static final UITexture FAVOURITE_SPRITE = UITexture.builder() + .location(VendingMachine.MODID, "gui/icons/favourite_indicator") + .imageSize(16, 16) + .fullImage() + .name("favourite_indicator") + .build(); + } diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/ClientEventHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/ClientEventHandler.java new file mode 100644 index 0000000..d847b6c --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/handlers/ClientEventHandler.java @@ -0,0 +1,37 @@ +package com.cubefury.vendingmachine.handlers; + +import net.minecraft.client.Minecraft; + +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.FavouritesTracker; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import cpw.mods.fml.common.network.FMLNetworkEvent; + +public class ClientEventHandler { + + public static final ClientEventHandler INSTANCE = new ClientEventHandler(); + private static boolean pendingWorldInit = false; + + @SubscribeEvent + public void onClientConnect(FMLNetworkEvent.ClientConnectedToServerEvent event) { + pendingWorldInit = true; + } + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.END) return; + + if (pendingWorldInit) { + Minecraft mc = Minecraft.getMinecraft(); + + if (mc.theWorld != null) { + SaveLoadHandler.INSTANCE.readFavourites( + NameCache.INSTANCE.getUUIDFromPlayer(mc.thePlayer), + FavouritesTracker.INSTANCE.computeWorldKey()); + pendingWorldInit = false; + } + } + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 7a3a6b7..fa9a3fe 100644 --- a/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java @@ -21,6 +21,7 @@ import com.cubefury.vendingmachine.VMConfig; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.FavouritesTracker; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.FileIO; @@ -36,6 +37,8 @@ public class SaveLoadHandler { private File dirTradeState = null; private File dirBackupTradeState = null; + private File dirFavourites = null; + private SaveLoadHandler() {} public void init(MinecraftServer server) { @@ -59,7 +62,24 @@ public void init(MinecraftServer server) { loadNames(); } + public void clientInit() { + dirFavourites = new File(VMConfig.developer.trade_db_dir, "favourites"); + + if (dirFavourites.mkdirs()) { + VendingMachine.LOG.info("Created favourited trades directory"); + } + } + public void createFilesAndDirectories() { + if (!fileDatabase.exists()) { + try { + if (fileDatabase.createNewFile()) { + VendingMachine.LOG.info("Created new trade database file"); + } + } catch (Exception ignored) { + VendingMachine.LOG.warn("Could not create new trade database file"); + } + } if (!fileNames.exists()) { try { if (fileNames.createNewFile()) { @@ -155,4 +175,27 @@ public void reloadDatabase() { loadTradeState(null); } + public Future writeFavourites(UUID player, String world_identifier) { + if (player == null || world_identifier == null) { + return null; + } + NBTTagCompound json = FavouritesTracker.INSTANCE.writeToNBT(new NBTTagCompound()); + File playerDir = new File(dirFavourites, player.toString()); + playerDir.mkdirs(); + File worldFavourites = new File(playerDir, world_identifier + ".json"); + return FileIO.WriteToFile(worldFavourites, out -> NBTConverter.NBTtoJSON_Compound(json, out, true)); + } + + public void readFavourites(UUID player, String world_identifier) { + FavouritesTracker.INSTANCE.clearFavourites(); + File playerDir = new File(dirFavourites, player.toString()); + if (!playerDir.exists()) { + return; + } + File worldFavourites = new File(playerDir, world_identifier + ".json"); + if (worldFavourites.exists()) { + JsonHelper.populateFavouritesFromFile(worldFavourites); + } + } + } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/FavouritesTracker.java b/src/main/java/com/cubefury/vendingmachine/trade/FavouritesTracker.java new file mode 100644 index 0000000..2c36cf1 --- /dev/null +++ b/src/main/java/com/cubefury/vendingmachine/trade/FavouritesTracker.java @@ -0,0 +1,138 @@ +package com.cubefury.vendingmachine.trade; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import com.cubefury.vendingmachine.VendingMachine; +import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplay; +import com.cubefury.vendingmachine.handlers.SaveLoadHandler; +import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.util.NBTConverter; + +public class FavouritesTracker { + + public static final FavouritesTracker INSTANCE = new FavouritesTracker(); + private boolean dirty = false; + + public final Set> favourites = new HashSet<>(); + + private FavouritesTracker() {} + + public void toggleFavourites(UUID tradeGroupId, int tradeGroupOrder) { + Pair pair = new ImmutablePair<>(tradeGroupId, tradeGroupOrder); + if (favourites.contains(pair)) { + favourites.remove(pair); + } else { + favourites.add(pair); + } + dirty = true; + } + + private static boolean isPrivateAddress(String host) { + return host.equalsIgnoreCase("localhost") || host.equals("127.0.0.1") + || host.startsWith("192.168") + || host.startsWith("10.") + || host.matches("^172\\.(1[6-9]|2\\d|3[0-1])\\..*"); + } + + private static String sanitizeFilename(String s) { + return s.replaceAll("[<>:\"/\\\\|?*]", "_"); + } + + public String computeWorldKey() { + Minecraft mc = Minecraft.getMinecraft(); + + if (mc.isSingleplayer()) { + return "SP_" + mc.getIntegratedServer() + .getFolderName(); + } + + ServerData data = mc.func_147104_D(); + if (data == null) { + return null; + } + + String ip = data.serverIP; + String host = ip; + String port = ""; + + int colon = ip.indexOf(':'); + if (colon >= 0) { + host = ip.substring(0, colon); + port = ip.substring(colon); + } + + if (isPrivateAddress(host)) { + // Because open to lan does not have a constant port, we don't include port for LAN saves + return sanitizeFilename("LAN_" + host); + } + + return sanitizeFilename("MP_" + host + port); + } + + public void saveFavourites() { + if (dirty) { + SaveLoadHandler.INSTANCE.writeFavourites( + NameCache.INSTANCE.getUUIDFromPlayer(Minecraft.getMinecraft().thePlayer), + computeWorldKey()); + } + dirty = false; + } + + public NBTTagCompound writeToNBT(NBTTagCompound nbt) { + NBTTagList favouritesNbt = new NBTTagList(); + for (Pair fave : favourites) { + NBTTagCompound faveNbt = new NBTTagCompound(); + NBTConverter.UuidValueType.TRADEGROUP.writeId(fave.getLeft(), faveNbt); + faveNbt.setInteger("tgOrder", fave.getRight()); + favouritesNbt.appendTag(faveNbt); + } + nbt.setTag("favourites", favouritesNbt); + return nbt; + } + + public void readFromNBT(NBTTagCompound nbt, boolean merge) { + if (!merge) { + favourites.clear(); + } + NBTTagList faveListNbt = nbt.getTagList("favourites", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < faveListNbt.tagCount(); i++) { + NBTTagCompound faveNbt = faveListNbt.getCompoundTagAt(i); + favourites.add( + new ImmutablePair<>( + NBTConverter.UuidValueType.TRADEGROUP.readId(faveNbt), + faveNbt.getInteger("tgOrder"))); + } + VendingMachine.LOG.info("Loaded {} favourited trades", favourites.size()); + } + + public List filterTrades(List trades) { + List filteredTrades = new ArrayList<>(); + for (TradeItemDisplay trade : trades) { + if (favourites.contains(new ImmutablePair<>(trade.tgID, trade.tradeGroupOrder))) { + filteredTrades.add(trade); + } + } + return filteredTrades; + } + + public boolean isFavourite(TradeItemDisplay display) { + return favourites.contains(new ImmutablePair<>(display.tgID, display.tradeGroupOrder)); + } + + public void clearFavourites() { + favourites.clear(); + } +} diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeCategory.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeCategory.java index da740a3..2086753 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeCategory.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeCategory.java @@ -9,6 +9,7 @@ public enum TradeCategory { + FAVOURITES("favourites", "vendingmachine.category.favourites", "gui/icons/favourites.png"), UNKNOWN("unknown", "vendingmachine.category.unknown", "gui/icons/unknown.png"), ALL("all", "vendingmachine.category.all", "gui/icons/all.png"), COMPONENTS("components", "vendingmachine.category.components", "gui/icons/components.png"), diff --git a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java index c6eaa48..efef577 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java +++ b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java @@ -13,6 +13,7 @@ import net.minecraftforge.common.util.Constants; import com.cubefury.vendingmachine.storage.NameCache; +import com.cubefury.vendingmachine.trade.FavouritesTracker; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeManager; import com.google.gson.JsonObject; @@ -75,6 +76,12 @@ public static void populateNameCacheFromFile(File file) { NameCache.INSTANCE.readFromNBT(nbt.getTagList("nameCache", Constants.NBT.TAG_COMPOUND), false); } + public static void populateFavouritesFromFile(File file) { + JsonObject json = FileIO.ReadFromFile(file); + NBTTagCompound nbt = NBTConverter.JSONtoNBT_Object(json, new NBTTagCompound(), true); + FavouritesTracker.INSTANCE.readFromNBT(nbt, false); + } + @FunctionalInterface public interface IOConsumer { diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 59514d8..bc0f5d4 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -20,6 +20,7 @@ vendingmachine.gui.nc_inputs=Requires (Not Consumed): vendingmachine.gui.alternative_oredict=Accepts Oredict: vendingmachine.gui.nc_inputs_overlay_color=FDD835 vendingmachine.gui.trade_hint=Shift-Click to Purchase +vendingmachine.gui.favourite_hint=Ctrl-Click to Toggle as Favourite vendingmachine.gui.display_mode=Display: vendingmachine.gui.display_mode_tile=Tiles vendingmachine.gui.display_mode_list=List @@ -40,6 +41,7 @@ gt.blockmachines.multimachine.vendingmachine.name=Vending Machine gt.blockmachines.multimachine.vendingmachine.name.gui=Vending Machine hatch.vendinguplink.me.name=ME Vending Uplink Hatch +vendingmachine.category.favourites=Favourites vendingmachine.category.unknown=Unknown Category vendingmachine.category.all=All Items vendingmachine.category.components=Components diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/favourite_indicator.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/favourite_indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..903f18a3fb1a74b41b746295e513e9fb8a379022 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9EFZXnDkGR4^uC@5Xx z8c`CQpH@zZv?_RRXv?DzRa!^5;?zmEewz~JfX=d#Wzp$Pz{hj2Uq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/favourites.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/favourites.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a94fcce57d9a326d6851f788e641ab631ccf6f GIT binary patch literal 1227 zcmV;+1T_1JP)z>%8+1ijbW?9;ba!ELWdK8EY;$>YAX9X8WNB|8RBvx=!KdMT000D5 zNklUuauZ9LGN=H@QjMb+ubfGuKUOH({_B5kVjP0|wpP@*s}k9EySuKFH=6 z4wZ}e5D}*qR-Xropt1=HafmM9m=6QlgY!YRc57!l+w8Vo)7& zhhMlazxzA)_c_1&`<*{RYt7x1_}>D=k`Vzs0vN#gL^S2C8bCStVPIbw;CtX`BAUvr z7QhzZ7oZnFYbK>s&;7K+KEGN3j|0C_nmvHNc5VLTzt^&_+Ll~V7H$<_AMkaxZG1eN z85^B{(zfIus{zmt9ICd>%(!~+((GQ_lHc7?fLJop4g3H+T5ZqeBv(hAfy)Q-2k$h% zAs`O4R@;@*Oit!6{=R>9+id~Fk`WW=qf}sRKqt@z+yexFHz`%WSo$%~Q=XLiSSVzS z0%>3hm;thY0xl<_seE04a(lfCJO!))3V;tV%Rs^M%$Ef(OKVM02pm8H9#8~AKn^$u ze4L1;77BGKzyaWWV11ncw<|{}-GAzt>mSquI09He`;vhbr+PDAs_Or`Fh(h@ZcG<0 zUb*7zue9q@fIin%KL-N72ZUHO5CEUAx%gU_{zbLF){xB>85wq*`T62e+mi8R004ah zp^r9fXgS>8ZU+4RMFBNUWa_q884a$JppR*=#Wj9J4L?UQK{-+~^a6FE-!5 z=CO61K_g)L5X~ljIfyQLikY-4M*o>ZO6>s`fY)tHUZ@FBhUf)8>5jDQ2!}(hp^zb( zO@Bp7XF{(*Ut# zq!qYMX+x^1d`>bsl}9U0*S#THTKsiEw8j;JjfrS#s#$k1<*V5LuxMrPjiAmP}N?zw5W-{{YR_J>R!Qm_`5q002ovPDHLkV1nlpC_exI literal 0 HcmV?d00001 From fd831c8281500fdbedfd2f06489b00da3a76d8f1 Mon Sep 17 00:00:00 2001 From: cubefury Date: Sat, 14 Mar 2026 00:33:01 +0800 Subject: [PATCH 155/160] Support all coins for NEI trade preview (#70) --- .../integration/nei/NeiRecipeHandler.java | 12 +++++++++++- .../cubefury/vendingmachine/trade/CurrencyType.java | 8 ++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java index abb1921..9960c18 100644 --- a/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java +++ b/src/main/java/com/cubefury/vendingmachine/integration/nei/NeiRecipeHandler.java @@ -129,12 +129,22 @@ public void loadCraftingRecipes(ItemStack result) { public void loadUsageRecipes(ItemStack ingredient) { setTextColors(); for (NeiRecipeCache.CacheEntry entry : NeiRecipeCache.recipeCache) { + boolean addRecipe = false; for (BigItemStack compareTo : entry.trade().fromItems) { if (matchStack(ingredient, compareTo)) { - this.arecipes.add(new CachedTradeRecipe(entry.trade(), entry.requirements())); + addRecipe = true; + break; + } + } + for (CurrencyItem currency : entry.trade().fromCurrency) { + if (currency.type.isMatchingType(ingredient)) { + addRecipe = true; break; } } + if (addRecipe) { + this.arecipes.add(new CachedTradeRecipe(entry.trade(), entry.requirements())); + } } } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java index 0df3212..61b7ebd 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyType.java @@ -1,5 +1,8 @@ package com.cubefury.vendingmachine.trade; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + import com.cleanroommc.modularui.drawable.UITexture; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.util.Translator; @@ -46,6 +49,11 @@ public static CurrencyType getTypeFromId(String type) { return CurrencyItem.typeMap.get(type); } + public boolean isMatchingType(ItemStack item) { + return Item.itemRegistry.getNameForObject(item.getItem()) + .startsWith(itemPrefix); + } + @SideOnly(Side.CLIENT) public String getLocalizedName() { return Translator.translate("vendingmachine.coin." + this.id); From 36891a8b1a310753f2440d4c5e2cbad7f45bbb4f Mon Sep 17 00:00:00 2001 From: boubou19 Date: Sat, 14 Mar 2026 18:24:13 +0100 Subject: [PATCH 156/160] bump GT to account for https://github.com/GTNewHorizons/GT5-Unofficial/pull/5781 (#73) --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index cc3ba00..c84b438 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -40,7 +40,7 @@ dependencies { implementation("com.github.GTNewHorizons:ModularUI2:2.3.39-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.28:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.266:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.360:dev") } // deps may transitively add Baubles, so we replace it From d6a076c577ceac34ba14608e6e8d8100e592363f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Gris?= Date: Sat, 14 Mar 2026 19:09:01 +0100 Subject: [PATCH 157/160] Impr(Textures): Adapt GT5U OptionalResource (#74) --- .../vendingmachine/api/enums/Textures.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java b/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java index 277dfd2..b79798f 100644 --- a/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java +++ b/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java @@ -1,27 +1,28 @@ package com.cubefury.vendingmachine.api.enums; -import gregtech.api.enums.Textures.BlockIcons.CustomIcon; +import gregtech.api.enums.Textures.BlockIcons; import gregtech.api.interfaces.IIconContainer; public class Textures { - public static final CustomIcon VM_MACHINE_FRONT_OFF = new CustomIcon("vendingmachine:vending_machine_front_off"), - VM_MACHINE_FRONT_ON = new CustomIcon("vendingmachine:vending_machine_front_on"), - VM_MACHINE_FRONT_ON_GLOW = new CustomIcon("vendingmachine:vending_machine_front_on_glow"), + public static final IIconContainer VM_MACHINE_FRONT_OFF = BlockIcons + .custom("vendingmachine:vending_machine_front_off"), + VM_MACHINE_FRONT_ON = BlockIcons.custom("vendingmachine:vending_machine_front_on"), + VM_MACHINE_FRONT_ON_GLOW = BlockIcons.custom("vendingmachine:vending_machine_front_on_glow"), - VM_OVERLAY_0 = new CustomIcon("vendingmachine:vending_machine_overlay_0"), - VM_OVERLAY_1 = new CustomIcon("vendingmachine:vending_machine_overlay_1"), - VM_OVERLAY_2 = new CustomIcon("vendingmachine:vending_machine_overlay_2"), - VM_OVERLAY_3 = new CustomIcon("vendingmachine:vending_machine_overlay_3"), - VM_OVERLAY_4 = new CustomIcon("vendingmachine:vending_machine_overlay_4"), + VM_OVERLAY_0 = BlockIcons.custom("vendingmachine:vending_machine_overlay_0"), + VM_OVERLAY_1 = BlockIcons.custom("vendingmachine:vending_machine_overlay_1"), + VM_OVERLAY_2 = BlockIcons.custom("vendingmachine:vending_machine_overlay_2"), + VM_OVERLAY_3 = BlockIcons.custom("vendingmachine:vending_machine_overlay_3"), + VM_OVERLAY_4 = BlockIcons.custom("vendingmachine:vending_machine_overlay_4"), - VM_OVERLAY_ACTIVE_0 = new CustomIcon("vendingmachine:vending_machine_overlay_active_0"), - VM_OVERLAY_ACTIVE_1 = new CustomIcon("vendingmachine:vending_machine_overlay_active_1"), - VM_OVERLAY_ACTIVE_2 = new CustomIcon("vendingmachine:vending_machine_overlay_active_2"), - VM_OVERLAY_ACTIVE_3 = new CustomIcon("vendingmachine:vending_machine_overlay_active_3"), + VM_OVERLAY_ACTIVE_0 = BlockIcons.custom("vendingmachine:vending_machine_overlay_active_0"), + VM_OVERLAY_ACTIVE_1 = BlockIcons.custom("vendingmachine:vending_machine_overlay_active_1"), + VM_OVERLAY_ACTIVE_2 = BlockIcons.custom("vendingmachine:vending_machine_overlay_active_2"), + VM_OVERLAY_ACTIVE_3 = BlockIcons.custom("vendingmachine:vending_machine_overlay_active_3"), - VUPLINK_OVERLAY_INACTIVE = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_inactive"), - VUPLINK_OVERLAY_ACTIVE = new CustomIcon("vendingmachine:vending_uplink_machine_overlay_active"); + VUPLINK_OVERLAY_INACTIVE = BlockIcons.custom("vendingmachine:vending_uplink_machine_overlay_inactive"), + VUPLINK_OVERLAY_ACTIVE = BlockIcons.custom("vendingmachine:vending_uplink_machine_overlay_active"); public static final IIconContainer[] VM_OVERLAY_ACTIVE = { VM_OVERLAY_ACTIVE_0, VM_OVERLAY_ACTIVE_1, VM_OVERLAY_ACTIVE_2, VM_OVERLAY_ACTIVE_3, VM_OVERLAY_4 // bottom right not animated From b1b1ba15b93ea23f79283cedf5a1b6b496ad3cf3 Mon Sep 17 00:00:00 2001 From: UltraProdigy <187078471+UltraProdigy@users.noreply.github.com> Date: Mon, 16 Mar 2026 04:58:04 -0400 Subject: [PATCH 158/160] op & wf (#75) --- .github/workflows/optimize-images.yml | 17 +++++++++++++++++ .../blocks/vending_machine_front_off.png | Bin 699 -> 646 bytes .../blocks/vending_machine_front_on.png | Bin 693 -> 635 bytes .../blocks/vending_machine_front_on_glow.png | Bin 325 -> 280 bytes .../blocks/vending_machine_overlay_0.png | Bin 740 -> 720 bytes .../blocks/vending_machine_overlay_1.png | Bin 455 -> 362 bytes .../blocks/vending_machine_overlay_2.png | Bin 875 -> 808 bytes .../blocks/vending_machine_overlay_3.png | Bin 413 -> 283 bytes .../blocks/vending_machine_overlay_4.png | Bin 478 -> 332 bytes .../vending_machine_overlay_active_0.png | Bin 1812 -> 1742 bytes .../vending_machine_overlay_active_1.png | Bin 791 -> 610 bytes .../vending_machine_overlay_active_2.png | Bin 2131 -> 1781 bytes .../vending_machine_overlay_active_3.png | Bin 543 -> 404 bytes .../vending_uplink_machine_overlay_active.png | Bin 426 -> 416 bytes ...ending_uplink_machine_overlay_inactive.png | Bin 429 -> 422 bytes .../textures/gui/background/input.png | Bin 1124 -> 797 bytes .../background/list_trade_button_pressed.png | Bin 3183 -> 3116 bytes .../list_trade_button_unpressed.png | Bin 3182 -> 3115 bytes .../textures/gui/background/output.png | Bin 1089 -> 762 bytes .../textures/gui/background/panel_side.png | Bin 3259 -> 3165 bytes .../gui/background/trade_available.png | Bin 316 -> 259 bytes .../gui/background/trade_button_pressed.png | Bin 263 -> 262 bytes .../gui/background/trade_button_unpressed.png | Bin 241 -> 240 bytes .../vendingmachine/textures/gui/icons/all.png | Bin 441 -> 303 bytes .../textures/gui/icons/bees.png | Bin 700 -> 588 bytes .../textures/gui/icons/chemistry.png | Bin 310 -> 251 bytes .../textures/gui/icons/components.png | Bin 736 -> 648 bytes .../textures/gui/icons/farming.png | Bin 321 -> 251 bytes .../gui/icons/favourite_indicator.png | Bin 298 -> 241 bytes .../textures/gui/icons/favourites.png | Bin 1227 -> 963 bytes .../textures/gui/icons/itemCoinAdventure.png | Bin 3166 -> 3002 bytes .../textures/gui/icons/itemCoinBees.png | Bin 3187 -> 3008 bytes .../textures/gui/icons/itemCoinBlood.png | Bin 3238 -> 3180 bytes .../textures/gui/icons/itemCoinChemist.png | Bin 3094 -> 2998 bytes .../textures/gui/icons/itemCoinCook.png | Bin 3094 -> 2977 bytes .../textures/gui/icons/itemCoinDarkWizard.png | Bin 3534 -> 3387 bytes .../textures/gui/icons/itemCoinFarmer.png | Bin 3348 -> 3101 bytes .../textures/gui/icons/itemCoinFlower.png | Bin 905 -> 784 bytes .../textures/gui/icons/itemCoinForestry.png | Bin 3358 -> 3099 bytes .../textures/gui/icons/itemCoinSmith.png | Bin 3600 -> 3431 bytes .../textures/gui/icons/itemCoinSpace.png | Bin 3055 -> 2956 bytes .../textures/gui/icons/itemCoinSurvivor.png | Bin 3084 -> 2964 bytes .../textures/gui/icons/itemCoinTechnician.png | Bin 3441 -> 3263 bytes .../textures/gui/icons/itemCoinWitch.png | Bin 3150 -> 3015 bytes .../textures/gui/icons/magic.png | Bin 459 -> 328 bytes .../textures/gui/icons/misc.png | Bin 301 -> 244 bytes .../vendingmachine/textures/gui/icons/raw.png | Bin 810 -> 745 bytes .../textures/gui/icons/unknown.png | Bin 504 -> 390 bytes .../vendingmachine/textures/gui/nei.png | Bin 4551 -> 3711 bytes .../textures/gui/nei_header.png | Bin 135 -> 130 bytes .../textures/gui/overlay/coinEject.png | Bin 927 -> 800 bytes .../textures/gui/overlay/mode_list.png | Bin 597 -> 582 bytes .../textures/gui/overlay/mode_tile.png | Bin 613 -> 593 bytes .../textures/gui/overlay/sort_alphabet.png | Bin 765 -> 702 bytes .../textures/gui/overlay/sort_smart.png | Bin 339 -> 293 bytes .../vendingmachine/textures/gui/tabs_left.png | Bin 3188 -> 3096 bytes .../textures/items/placeholder.png | Bin 3125 -> 3012 bytes 57 files changed, 17 insertions(+) create mode 100644 .github/workflows/optimize-images.yml diff --git a/.github/workflows/optimize-images.yml b/.github/workflows/optimize-images.yml new file mode 100644 index 0000000..0ebed01 --- /dev/null +++ b/.github/workflows/optimize-images.yml @@ -0,0 +1,17 @@ +name: Optimize images + +on: + pull_request: + branches: [ master, main, release/** ] + paths: + - "**/*.png" + + push: + branches: [ master, main, release/** ] + paths: + - "**/*.png" + +jobs: + optimize-images: + uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/optimize-images.yml@master + secrets: inherit \ No newline at end of file diff --git a/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_front_off.png b/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_front_off.png index 00dd320a5b9f04453883720c75852025dffb97fa..145c55dfd4a658f3b5df03b4289cd74b927c9749 100644 GIT binary patch delta 561 zcmV-10?z%r1%?HXV1E%wL_t(IjeS!+ZyG@moejvTEW3ytn@Fx5$r7z2q_pub0L7w0 zxhn4Bf)XTKvXJ>GoD$MTNKQ>88r%OMO)R@fxN`xd2#y5iZud6x27@4m%;~f{Gdr_y z-ps0MwQ9B2q>ZM)*JKQS!~1|t$hLredd`n?yhfoEPfqAx`G4K($(qaMs8TLJvO{*? z?2ZyZqRY=`58I)oPLuHf!y|5^zQx9v(4*bumODk%qJQ>D}GY_U7iJ;BQ`!lF201>vekV#>AGG@`p@*6yw=c@%9x+ObR?_%^cQ)S00000NkvXXu0mjfu(%h9 delta 614 zcmV-s0-61W1-k{1V1GtQL_t(Ijct>`OVm*i$3L$XyX4jOXMaE%D^esFUhGsCF9}NG zA*DqjJ4gzG2rj6kxa=l*SnTIH%%ToO*F1OflGLqT4@!rmQ1{Kuz7E(WMp8T@A zOD>l~RjF31EH5vU&1N||I->DnBPPoC?`2#*pAS*gf~qn(`GmICRz7WS6UQ;$d%X9o zJ%65v(B0jQTYp+w3Q-hMtJP>|Xkch)h>eX6R230HL|9y0OhoAI?ZwT{FN7#c1CUCk z08l-3qFSxuy+=eS6bg)tjBtE>jEW$pl*?sYE|&}Gbi@Vca2Ff^W>zm05#kpw5)nE& zI&ibIvmu?12%$zQm7-RwAtIPr9b|b22l3t$$1wu~ z19wOoR{b-;=u3oG9>@d4GSO zkG$klQx<@yzkhSHvlI7td_26`+9H$5oD z;D#Rz2Qk6Kkh21_f7bTQQZIt3p=OABOchn*50UhWrd=TQ2LJ#707*qoM6N<$g0<5o As{jB1 diff --git a/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_front_on.png b/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_front_on.png index 077e2165b93b2cfdb2c9474cd26ea027700402ca..1acf03308beccb63b4cb524c1879ded93ddc2886 100644 GIT binary patch delta 550 zcmV+>0@?kw1^Wb$V1EWlL_t(IjeS$iP9i}Nt^uN6jGN8IAAA8ladpE3tmi#IG@OWY z(wiPQf?<;lk)MNmgna@%Yr;ieLIW3tF-GvPxCzKi_w?3RECd$VnpAqKx~uxDud1zb zxonhDq_iT>Rirgk^S?*hXP?J=YKGz*uOS%uvorcveswysrhn6EDiw=Ue#q{Z-9Z9K zXnAcS!6&v~of;$XCW2b6*682kSgTYjneb+qjt-A#duwa7d3S$LnM_9D_WOOx<#J@( zHg&sQT3B2l&80OOO|tU&yxG_Y%fXYAV@YyzdrQm>xvnev*Y(z(iW9RLUUp zJlWgd7c?L>9*@iaunfm}LJ4~290(V`UxWu-fD*2+u75^*wR)X)c0N-;nB@BB2|9uj zzCJ&T)@pUi-t7%8VEzJt(s_HM@W-VoMPMuzn@SoBp33So`5}yByWOU0wK@|4NCa`; zhmJ9@F3*p3VB2PWbyemXtfH+58h?3Wv;V#KPKG~>vB%s!IS!M^#zW(gom!F%dO!AT o|F+b{${&ywp1N}7DPw;A04F-GWA~lsr2qf`07*qoM6N<$f(8=-?EnA( delta 608 zcmV-m0-yc+1hoZ_V1GbKL_t(Ijct=bOO#O*hM(IEwW+PmXMbP>MUn!;jjd|qra(zt zq%3` z>o#t6bv3*ymq}l`d`9G3b&uKESqgBJChG5>BweV$2s>+imkLk!}`Lw-F9LIR?@!qq# zvXY3<*Vl(zTz^~)Q54Z^Hc6+`jEs!1zP^sCA|i+g3kwU02m=EHxaZFcA&N2pq*5sW zR8O2}G#YsC5fMtI5@Tay)a!Lr1Tp3C@DP{J=R+nFan3p1IR}85wF*Uq`1R{VgzoNc z+}zw;$YdfyXp%~$Xf~UO2xiv8SYBREMCk9oiJO_334d?5w$51CvTAr3?>%uGGc+`W z_r8Tut$x8xPfv&U@7^W;1O4%pJ9qDr)L?IapWfaZxT&eB@bSY3QWx721^zIP)oK8| z`0y3~x3!>Fn%0Be1ix!{Fc`8yg${2ms)q=V}jbVqzk!t*v2Z zi8B}a=DOcYeV#8^UO{r|M%vJ2x`i&`Y!?j6GhDUQmx`f?~evC u!Nic$0<*u?_S8}@f~lcqhQB@g);g80000!0 zIZ$301_lg+lsF8Ew3N+v|Hp2+{oildwSQz85WMErf4`+y|2Z2?KmT{MJQytxMsi9V uEz$-uK5V1Lj_L_t(oh3(Wq4gowaAr1D)jwiA*Srls=A|!H*`<_rbRT2a@P3tq7Ht8}NNl n1i(L25uV9`E93@zA7tkZNpP=_JQ^x(00000NkvXXu0mjfSw3Qa diff --git a/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_overlay_0.png b/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_overlay_0.png index 01f9b6ac3012e5654b7e0f1f6c88a0e958a0dc94..e982eeec738c1288d9942b0aa853c1d4d323840e 100644 GIT binary patch delta 635 zcmV->0)+kK1<(bMV1HXlL_t(I%capCkOuVl9=cT5>^{qhD;5ttqjen!F8a5u?!%hHnR>Q`; zxze)yIPkxfmgWC>!QaZ1Pf}$#2MgfMG@%t8tcW}DtXCMuDk zR?nc-z<23>eo9xg!Sby|e;z0WRJ*rdeWC<&nvp|dr_|i^rSp9)J17}IzQ%&-m$W-558cQ5} zlxDGHxDp4X5f?_)5=k;YN|l_3>4!Y;Fmdr{4zk@gzZTgNz_9p+d|GiGZMX+LJ; zKn%#SfL;Uc^b(%fjU-5eyrF_zuYv9tLkM9%k0)#t+JE*E^8cdqT{sRTYCtOmL6DLc z?c)9UQBL)=AydZq+CR#YQ->heU@I}<_pb4&Z-Mr*syLvKLxLiPDM7^6V#ggwB1Io0 z^u^7@d?wB1wYV%7=p3=&82W%D6y&+1fz;r9(U$@v}OxK)0ll_TfS@l9pMFKydDX^;gV1I8(L_t(Ijiu3BNYeon$MNqrx4cYub4~|phDM4Qu?LG3B?=4- zOR)=GAdrwi3<`=6L`;RSQZ#x{Ls%IlX(5C}WSHGFvt}Y;rqX84TbnvJ|L)S86MQJ_ z_jKU!`*7fhd_Eul6Oqs7L!DN(X=M!|rMljwjllV97k_DM{ffe%SzFrs=KxR` zG;8zv~p4{`&=T(;JF3X8~B0=m_;#ne{}okW_+QwV#JirZ)l!DKqE=6JAjO zL6%W+v<>`}q#$+KkctGhWmeHUF~?y47z=LIM&LmFV=`>j0LWzEh|VNlI*Q!qV$04- z+#U~8eWlo@tba^8WBfpQp_G7cO~i)J5*fOH$17%8n?pj-TWa2&Lb;Sv2WpEQ zq)F29DUV7#8wIJVGHJI1!Ad(tZW_5B^RH1EEw~O{J@<{4l-qR=z?8j z-D|?`3S&hTfp^Z%usMpm$F5+DDWHA8fc0Y+D}oodKG6^KTwf)8;U*D5PWCk$nOjzY z$cOcJAb-{Qw~)jgMvfKnXe(!omkAG$7;HfG{?GqO#TIjKAq)U< zG_#JwF^CVsk`53)h(^aCakv4vG?Q!qx@Mvc2rq8=?>PJPf0$QDHlT0$jQ@et*1)|1 zQXu1a7_R{+fw*u(>;LsVV*lsXO8;L_FZsVE-x{Y2ki82x;D5p*?*B)pF#O-r%J6?< z6T|;0rD`ZPAqO(6N-_!t8}R=O!~aKX8UEi~%J6?fBg6mxB25&V&^2KiaGc@)ll9F1 zSFH5^zhJt}|LN0Q{|jiv;?#hVl=U+={@=DG;J>6{6j+grVFW==Z8Uw;8oNkly z|FhsUKt5I&5r_*nwEpM2Gm+ulM^*-Arhg1iJ}5Cvz1V}*1p-=#u!0+KVG;NLub;j$ zy#L6+@b@nR!{g6t46UaZ!fis1p*y?gpt$7M?KzB$|IaY|fBcYv;rkB;hU<42818@6 zWSI419^9t0?P{Hven2tcIK%&^FPIsQ{PJP=@$N0d_y3#>l~W`bzW!pvssUY$Q9pCz z|90>B49T@z3~xSjGKlkjWqA3S8?Po516Wm(F_JPNO;`;eMH7kvlxAlDCabyO-Lsh& P00000NkvXXu0mjfXeG89 diff --git a/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_overlay_2.png b/src/main/resources/assets/vendingmachine/textures/blocks/vending_machine_overlay_2.png index 3a3d66534301fe4810a4870e43f5b1887b8c2573..f6c257480521a55f778e6f2c13bdfef305981992 100644 GIT binary patch delta 724 zcmV;_0xSLN2B-#*V1KhoL_t(IPhF5*Y>ROe#((d>?bg1kC^KwJnE03k6W{DcSY`=k zL?UtF;~qCeh!7$K5f_VySV)9~xv)fBNDxXa%d(M-(oO8kwwA56cJ2Cp{$1#rv`=zw z&N=y==RAs(5`WbNdFgnBy23`>PJ@{~n0>y9Gea$J+_JPNSaqK-lDopCX^D8HXcU;gaJqZ#3Vou`!FM3 zJ_R3@30C!J6!%rU|+$zpxDHflM zqQ#=DoZk0;(FNi#n9ZwlUnuP?ryw@S8gZH0cdh6J29dr38rH3#`<)M40ZV~I+ibq? z*ot8&xd2fXW7d;K#(xTaHmgjS62+%ed2om+#rpruB!4*lN&NL8EF~|*XTcGqwCNA{ zX}P|D--9mFwoTdEIHk+e$PB=lK`#9izrV}w5OlHV+!>RU4%ZXbiVN+ z6tWTu{C+WL_t(Ija|`ONR)XP$MNqwIytFpSvjUNi5g`GYAmUC)iz=; zh85JJjE)2n9f=B}=!6>uOS^Pfx4qa!TG(_6J6vRek`+Y}R$3ZkIUO`lMjsS0C~3513|Xa^CZ z)7FZ+=S~Fpdv^>=f|q#LHlLJvr!iTZDBhL9xm6X^yDi+XZN%jqWJf^*Yf^2jyI^KO zeiQ*N=VhXAuYbqAZY_CZK0Hyb;)R4v9|gPmF)auZ7!7X_ zlK@`3ft9D`(-jTu$<*fJ&Lw|>=XyIW|Ot$|yGp7uZf5?JMZkY(! zuhbw2FFVs>CD>8RuZ0&8NVF%El0N*5c9|;&mSU!+JjFmQjE5{6rw9d^62IpX2|@J9c!!d)~350N9Rf#N%w1{sYmi Wh!ODSKeVp^0000| zKS(bFvH_Y|$Ke>H8OD}$I1bkgVuQr+8i1@B#z%G`UIVVZ{g0s;gh4hFGytR-Jq%#s zK$HQPyI zQWOIN0|Ud&dCM67+}OnM>CIV2Mq~p%o_z~f92Bam802Gx85kHC z7#=Qu%OIe|!0=>cHf{ruHN*IO?>&dRP(t4ww*hOLEf|7pPk*3jW?*1onAdoP;m7Zt z_zjpBpvqwF*N74Z3=9km(`tGdI9S~Y8vygdhieQBN%at$*R8(7@Z#c5;tYWK5!vQ1 zFCQ~t103(qV>jUFrh0~@m%gAxABJXDcZM&QafAT_0|QDR;sO|6$Z9EOh}Pr5s`pkkwL*5|9C?T3qXlRiVdIy Z008v%3Gn6TEmi;k002ovPDHLkV1ib;!Qf|DFK_ z6sv?cYd(_%Dgkx|)+PzKE5%G+uYkax!JwchieU17O#ZI`*ijqx3Yr@g^wIC$XHY;= vchM7RQ=aGZPcU?fK)}B}1`U0_1WRZD6%3w4nhV%g00000NkvXXu0mjfg5GK; delta 393 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 AO8@`> delta 2059 zcmV+m2=w>$4bu>iUw;SQNklmCR#ae@!3N|2$MpVWZsEBXnxy#;lS6pOw z+2`#C(y+Uz(0D%Hnfsr6&b{Y1=SoCTq}QlV#m|=uWO(P|BY(B>QXt5(4zTuv6pSqo z*}K0SyF*0k6N1gCM6}xw?wmp2P#}@~FOav+K!Q03FS8x3p)VzYrKq)Ljvp<+VYgwD zM1ttR%W?-qD>cM^reaTerRsQ;-jmwKP!Js`JTXXUs_DVlwY9{KY(WH!m47mta$aSgqnSIx<&MA)%lxSM z_yDrk1VTsYxU^M)-P?w2XbXyAt;qVeAp(|qe+*Ycm~beR`)a2rSTWW}!rtSU+w54p zY&1Us{}=-)i&aFvV!_m2xPj0Yo{_7E^gOZDDJru^+TU(N5& zYcn)V`hP%+>B)~v5CC^`6{H`Pq0~7|VbN@Xxna399S`7UVQ*&S+#^UP;;@3*2olMU ziztGpFT^j5r@r>8Q((Hl(1*DwqO3%}EJ3dn@sdJh7})H%jBQUc$zEB2s_{xk;Enl1 zv7M-9RCF=JBTgd%J-i@F4mMlI&FAeC89)V-R)5LSG*xy41}>b#?VbC0cR&e~V$Z^l zf!Jsd>^4XH&0-pTjTZcovE00JE{adeWNJ091c8%Qdimxj?#iE+IZvPSz&TZ1AA@<-@eLJmQP( zcbOS~3{kZ6&U2-KjuUV>g(?Bqd~frPdkygkim>;ouqw0rRH?@ockip}nD1?Bc> z^o>W|Kxxb7p0XePQrEEM>SK-jgFm??GiU#jgAl-Z7E?mL6B>P;iV_MRa47k`>= zf%4X&P-;4Xl2?k^WbGCxBQxV@5MBV3$wy^0xq~uKmW%2{*Pv`SW%AYU3sBZy`Ts#F zGfm_b&k9nO$PrYPuArDo@<@%YB3W_ksi2&*rO~hL0ujLi!_TX8d*lZ%@Vg~(< z<%IeRcuGAOu_A$HO@+G$PXI}W2Y+@Ii*@6;9x#>YmNJ4o1T1!6io!NY)X7Wj23) zdkX-o3*O_<)!~?H^3m0oxNT=s4#D1L_TJ23__+5tbZH2OkDQ_LQ4llZi+|ieIfh<& z%ncM%HV<^M^c|DQmXjm+ChtDsz6~JSp90D$^o`%UK7n^#5vr(_j1N;2zbYQH-IM-7 zH=hnl)n)X`B3DrKA+h*tR0J+6P%3jI)J`wKtAB?9gGtgQC`svw+*LY#NFVm|BIUwCA~Nc`1h}eHCCeo&z{8q_w1n=^PL_8I`^>jp4u zPZreeLRas!op=1fK!36%hwwl%$vg5{@NP1XA3tVm-d!dSEN0`xZ`?rn7G3>uH&Be( zC?Cf{{AQ$OuQ2PbucMu0hGUm&KMfM^I~i1}NoBq{qKh%qjFl+Xkj}RW% p?!h^63ObKItY2A1i}teQzb$ZU+sOma6aWAK07*qoL!3 zNG}7j0h(FI;TWVD#+GzA4%ZA~gT(L}fUFtDM|L4z1FpUOkD(caK{gXK0Hhf`3}E3v zlmWQ(nz&v;J|2D2_%m3w>KL3*^_katN^rXc9ZB_Q8<-urqFj^iAy7B-3T8s>}lC;5S P00000NkvXXu0mjfMca?3 delta 457 zcmV;)0XF`W1D^ztV1KGfL_t(oh3%A2D1&hr$3JiRvx6iY=CI_j)EX`hii6uuBodL! zo70rbu9#(U8aL(g7NR6ePF7YfN+FH4a3E1A2Z<cCxhCY2|&6D@6GJtv+JYD@<);T3K0RV~^7k2;v delta 91 zcmZ3$yoz~(1SbbG0|SGGE`RVwMQ27gLr)jS5RKsE1UKdzED{qK^cdYV95@Ub8S5C` v1deGpEM)a%;CjHs(GbfZx`5Nbn3>_(1jdbzb-#Q9n!@1e>gTe~DWM4f=!_Us diff --git a/src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_inactive.png b/src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_inactive.png index 2393590ed5786f08570f860ba0b9e659d76cc79b..cda493b205eb841bb4ee9ece6057868685ee869b 100644 GIT binary patch delta 83 zcmZ3>yo`B*1SbnK0|Ud`yN`l4D!Mb;X?nUihHykD7c?@lu{1OC1V}VFFr;y4YHBVr noYH$iQX=cYEkhr-?XnE&PlZDLsyUAUbu)On`njxgN@xNA^352; delta 90 zcmZ3+yq0-_1SbbG0|SGGE`RVwMR!J515X#n5RKsE1V`o@ED{qK^cdYV95@Ub8S5C+ t(wvwiqAsv3V9;w|xWO90IE#Usn?Ws}Ni*?Vd@;}v22WQ%mvv4FO#rW`73Tl| diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/input.png b/src/main/resources/assets/vendingmachine/textures/gui/background/input.png index 67cd44ccd73722a5a235a52e372625823831ed56..d1f01f71c06c8bf9eff4c244d06c173829fafb8c 100644 GIT binary patch delta 714 zcmV;*0yX{Q2%QFyUw;CqNklQalKr5*KFDJ<~mdh!R3B z2`CCG9^6n71y4By3<%;u^yByiJc>s>m|f$paf?e_;!Ior_v*c_>1Dces3iTW-v9Sr zbyam#6h#WQ_kp@ud90#=8DZ0GQyB*ToQO%9)R|RL<%x=jaevS9lmM?qK<%B18h^=F z$o?5?w#eFSQ5S2Q*hY)@t{AI*Fb5z;j|0=gRRP}uc>Qy>@W#H__CJb$OTT=E1z$}D zNV`{XE-G(MFJ2Lg+W-%i^5Iro9wG}Id^c$(&Fw<}0&cJH!+WlsXN9vL8^T}3V0m-t zYy5HPtq9#yV1H?__sj$`{JaSAkfQK+F*td90X-n}PHR@nuvBd^7KMWXPKw||-n=Q0 zBCvaYNILUcXISVQ!J3V$e&q7jL+XigOdH?fP)Y#=tLM z4N}M1Sz`+ld-TM!MZ2K=*CeY0?0QY42<^l-Kg|C1@Yg??BH;nFnSD*!|A2F`o=b94 zU=|n!EPq@UX*Xl9$^IQx`cPD#>a|_2@2BGQ;=r7VV_A$$Fbf^TdkTM~ZXVjXj`7NW zSL8u)V?O9$o_;Qv1@{1sL9Ydu%_ou8eK}sMljQr!^LfclEx(&~S1=3j#%(Zd+-*$3 z`DFX_J7p+_5&Qa!bPK@@--`ETt2vm_5 zD1)fEg%^KMSpkiQ8XJ{l=Kytu2I%gG|cL**X5&VfYd+@pGN#V1SJS2*=dcu=ZuE+ zS|)T3Jb!uc;_Q1iFF^0KM!t1=kNWHQz|TQY0X6a)l7G5BatbCPC^2e{eCUjgpJQBS zK_!<5FYN7u)M^OIY_&$dbUF|EIX?5(yJkBJYRfFL&`8ZF(xAj6*2qUoIb99BZVVE= z9l<~3=lC=peEodX)qA>!cqz5o!Np}>=3#5(W9PiXU(f#ITiYeSQdbXbXRNwMUT}W* z>nsQTJbx(9L4SvfN7<`3jpGBmx^7~(PRBAYK~QF!HS&cMd9rH*@8}Fmj&K_0Pw<>I z^18FX*Uxb%o@s3cF8#!AU~l{YdA@4{V=ZB+MNJS^c)%Jt2ryDnqEe7r(+RE3Kr?`e zoTwI54|2%Qfzlm;y=aZR3bB*RIXva(dE3tsoqtdQ^QR!Ja-TKw6~L_}C0=*bK&{d> z{)C{6XN^dqsEp1q?&m=zBAcKL!D*hgM&4+#I=~J->gPDnDp50la0Qx?N}ZuJ!#(1HuXfB_6j%_Qg4ufgOCC&hoiVgV*iKJ_+G8 zcYjzT-xrE1ok}xJ6KXT$t&vipsD^c#2|pi|w;4cf8iF$0t&vX_GnNE9_+5ICZ*&^G zo{r3KvqpX>6jdMKStI8QMYUOHIot}gIUi*jPIHen^7T^sR|GrwMm@;U)GA2yM^{@| zf$$ebtdR+4Gn87xF+U65HPHCOT?$ien}2@|cEUI4EGLuwkX-4qnS!v&2oUHDKk9S@ zt)GMXEQD1yS|i7o)4eL#!TbFj=e?e&n;U;cp9f9QYa!7ab$5LZ!fN~a`_EtpPxyK2 zN`p>E|2YzMZ|zL94kp_d{r?7TjghJn1avl9hf_ck=1-BZMw7PZ!6Kid%0lALMKZ;Bh%H|02zJeIz)A7*q%(i#Ej2-(JCM8}^)l{GVg#idWUHx3vIVCg!06TqI A_5c6? delta 411 zcmZ1@@m^xXeXjayPZ!6KiaBpD8x|gM5MVecx<;6v(Q?wFuk(Fwrm{R=Abn7!`0SbV zhMj58KHHps$!C%F-u8R#|8pC@+udbxU$gbuEinuRRW|AXS@!V{$Arya_?!T`hX delta 410 zcmZ22@lImHeXjZ{PZ!6KiaBpDJLVoW5Mem@J+pO5V~abF_TDv7qK(?6YzO1M85_T6 z_&jsw_u9V){%`$0@Aa;_v>Vm)^O}^eMHS!QE_r}Qz}VpogCX+~(i!#SX``C1da_(i vmi2XKKiHgKv(?Z1py7SvIed-#A8>O_7P9bhyJE7H0SG)@{an^LB{Ts5GrxnD diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/output.png b/src/main/resources/assets/vendingmachine/textures/gui/background/output.png index 8aa56a6dc16bf1fe77f6be54bf408a366bdf39b6..08ca9e6ab96c7a2249544b90e76edba95771d35a 100644 GIT binary patch delta 679 zcmV;Y0$BaQ2>Jz(Uw;CHNklXx1w&k_kbv~8u;jG{)lkTQGY;8zGQt$#?JRQD+;sWR{E0= z-ST}ZI3Fa{z8v^?@g-9H1(V`Es66*G@JTOft_d&9heM1zl2ANRL6D8h#KN$|!@|EC z9QkeG^I7}cW*mUSqK8e zChEma{C{~7e+k1XE6=QvB7ALj2|62ou4)j;ca|kTC#vQbCS45^!@v&x!np&(g(0g| z)B)>+opyU~`3Bv~L5o0c$Gs?=PDT~=;=%sM1@Coeft&2g+z`g&2*_>o&5vx&5B*X+XlDca2#SqYh$4V2##ArfO2r4F|CKx|}2cyPLF#1vr>PYc}wrpE5 z(28KRo#}S34|BI))KWH{w>$To|L>mvnR|s&ic(^AzxW)e=zlWR+EVI8Dd5%p;$xrz z$OAuinQFuT3Xa!{shf@IHcs|r8Bgtl>W$&YQ}vMA2YoNjD$)2)w{ouwtf3Qy@p_?> zd*R#;SpE*gZwCZ?e zUeSUvE!YaVU7(%#4k+|wxm>lLXA&>5-$;ZruWN_s&3_OKa*yYzlk*1KuGl0k-q-U2 zz-ocWB35~h`gZEy9!s<7j}z(x+Z7GQQocH)XCAj9I1fQT4|0~BEVGWa>7o}==%D;f=xFN_3~NlYtx#eZ{h8E;A}T&r>L`yd#g(Q}k*yFy5dLU|QLZVYqAETsw z0#M-R!0+Q}&r$7Hfo)gpimhOeu~b8Yupk)ZUe8gV0j$aiRVE?2c)D$4zk?csE^`9j zWSAV2CWvU56AZxUS$24idKExqI;jM9R@}nwqJQ8NizcA9D_)4L;Pv9cW`-7S_8fIU z=RY7Vj>{xargP52=+Ep1_KHj=t?>*yi`J=vwzr=q&rv6|$o5#81BN*}v>1L4{9d+s zjykOC9+ehHWlGzwM>En*i&%3B6{)_e(?>i z$K#%(j_BldMuIP;1;Usgv={{+f*b_Dh4)_TJtN%=g>u!@N-d1B891QZ5=V_=zdUJ_U%lYVHC|^+YZx&@SV?8rR!1xsy zy9mJm3q42usr9qcWWUICvfXpkLH)5tnhcj!hA$6P=ji zvgn$Xx2ExP8)c@xB3-%fnLUPQ{q9(I6v&o+s(NqT5y5V8wMt3ndwy{C*`*3?qRrfn zJV^|O4H6DK3Ty(*9gIg9uyX71O9N#Mfry|n1WgfWmH;A5$JFC<99B~uc{&`iO2EAM z;JxA-iF@)7LXsNdIj$!ipAhux8e@B;qKZY*}p? delta 487 zcmcaBv0HM(eXjcBo-U3d6?5KR-PjxDDB*T-X2Y@<%@by6v}k$AE#g(FQkc#Atx8v& z@2^U+-xqb|+LKq$eEzxT-uv$rd*hOCZ)2RFvevZzZgH)2@wxqb8~aL8FtZDf zfT6IcMDgr)Jsc>2H(*+UXX3#{e>Ls6Ky=e@wSsL$$c#~&NcJOBLN?g#Uu ev(FkH`@!U7bwp*WG2dhcAn&ny$?Xuxl4YnJKawIC0KN5svXL~gb#oGtk ZB|q~6C2~&HLeu~N002ovPDHLkV1fc+P+kB4 delta 228 zcmVjv#>WU%Gt;OqwCp6I|64x{mNoDBY8Fo8fI5C{YUfk6C7?6WfV*;^%7uW%+Az0*+T1F_2k UOP2-Ega7~l07*qoM6N<$f^dK?Bme*a delta 109 zcmV-z0FwWP0*3;Sem8VUL_t(&-tF5#4S+Bd1;Lk~fa0JSXaEBw_}2s#@xx`-z$n<{ ztS!m%)Haf P00000NkvXXu0mjf(`hjX diff --git a/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_unpressed.png b/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_unpressed.png index f94c9585777e94e724e5d59d8889ecd6f72e5f51..3226a22ad2aa77fe3c4a2e1b47292005d3710c74 100644 GIT binary patch delta 101 zcmV-r0Gj{t0q_BkX*P06L_t(&f$iH-4S+BZ1;Lk80RaP`;8Jiv{cA$Sg`ZgiqhOP} zwdVnk)JIjV^zkndaLB=72YJHcN(gE_jdzJzNn&l00000NkvXX Hu0mjfM|v)k delta 102 zcmV-s0Ga>r0r3HlX*P37L_t(&-tF5#4S+Bd1;Lk~fPeu|&=ed{|C*p8ez?pU7zLYL zwIx~3+FH_!iER>VX``hdk)JIk{Uerr)Yg)_R(R&pQ#%c{y!UqlOLRb+o&W#<07*qo IM6N<$f*)rrp8x;= diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/all.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/all.png index 20ae98fc1e6bbac51b5b6018b56035c12b66c6cb..fb0f7d28910ea989abbabba05dbf5d4c55e7f6a6 100644 GIT binary patch delta 216 zcmV;}04M*s1Fr&*Uw;6)NklPRP54w7tg)RdtnMacU=-guPisD?|*?B1*jJxz|eDn66J-tMQ)JM?JoRWr1JrlKnyf- SrMfTx00006> delta 355 zcmV-p0i6D?0=WZ_Uw;8aNkly=%g+V8AW^< zx@49tYM_IEf==S(kiiPRAdVTFbaGa~sp3nPG>8P#l1}H8BS|lpApVwvrylU)*CA6c3tePj?qhLG=g+Z#=*@u0Pw*bb000!z}i9y zGZP~eWkK7xU2ku(8#IC`#}=7nkSl{KC(Vw*(q5 z@;sMfq9_$Fj9jDfqV&owWTE$Ww^&?S8N#kE+Ia1B(C_!MpA8E=J3WCirzVO3AovL| zTdU#u=`kOSqfud2QF^$aL%pFA-}f;XgqcO@`32X8{^1M_#76)C002ovPDHLkV1h38 Bp*8>j diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/bees.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/bees.png index 09fad74fa093a8e95071c41a8569b931dcd28d74..989104d0bd9b128dafc6cf07c70431f65fb89a3b 100644 GIT binary patch delta 503 zcmVr*{c`tN+O3=Lkt2z4uGNog_NS!5Z{2(idd5>Mvwj%Uw0>=1Zu%VjE7&c zlg)hgd1juh0K`E?{CCjGuH)oD!03FQ)NqRQNSfIEDt`rb&ws6u9vfuyQ-N~vJ-5b( z(68O#k3ji!6_x4NKb>{Yvv;H)4Dzj1V6#-@?)W{0#ZUIB>%_40Y#^>y}JL323BNa{L2%5NDS?N?ah z^eK{O&hCGPPJf%4G%HvrsIl^}iS;?j*O%>-7TPd7yi5#Pn3Gwo#lrq)D5r9WmN18d ze%7A&DbDKnngm9x;CoIdVhGk|o9XHekb54lx|qsCZ!}iF-Flv$7t1Uy9>oZ0cp6;z z8U^_o8?@>uWo*#?z{f|2Xh|H~fz}+8#!FXJTVCmBdT^kD&RBpq6FxenUEyP&s<8iN zL}8wAYvqD!f)3`29!Hu6fo@A}%x2F1iS^1Uw;BeNkl}P84(a2A(bP^^&k!+ROpFW+ z&A}Fc>zdxnsedzv$d2E}{aPbVmm94p|0Vz96gfx}1p`8g@^6_U0`8V==6@bvatQjd+%Shb3Ts}Z<%9q^({#zsjuNX?Nf9A^)5 zuf$1lwLcHbJ!Iui@c8B$GD=jOIuyqe!NL9r}W(qFhD9AuD6nbk>y_Iy>!-*8G zg*nvg^va8Y?rVv+=~*=$%XW-)(1|Ne^qHh%z6nHcc18Qb*$0000sMJVTmwE<*Fvx`fzT}M?HmIASwq9S!% z2r>wUspi5678dFm2s4Z#13_Me#V*J|id_gZ^bORNgbX9vKpbKtgeU_^#Q-anSVi>k Rb-Dlm002ovPDHLkV1g`AKN0`{ delta 222 zcmV<403rYT0k#5=V1L0$L_t(Ijjhq44uU`&$MG*4o83Yp@Bl}lx>+Ro7|sXq6|6L0 zfnsxRScKwc)xafnBWtIhfgR3(9y@;R{^9fg-TsbJiXr24fpHxF+?40J(+kw-Vp6p4 z=L-&xStn)$ZdVPsnL{Q7W6v7~1V}ST&w@)?+JPFyC+r&nP@^KENzD#X`(u!d`3 z9|YX0%D!P;*X`UI)LFVNSKl87)Rt<807*qoM6N<$f>?QH*Z=?k diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/components.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/components.png index 23359d75d5dd87fc1fc218def1f22367695308af..1771d2d5c74803a601b34a13a475504b2e72f045 100644 GIT binary patch delta 563 zcmV-30?hs31&9TZV1E-yL_t(I%dM2{Pf}qR#{DZ>wW8(=l_ZVY0y8(uhJMsKpa51w1(U$yWAMA1)nUkgwEHOI5b_kMuVs^M9F*M1hWgg|8RveyJ1R zt)lGL$RGUBl_fNooGBBM3mUA*azte&uuVt6RPj5>{3)q?jf@7{NR?TUi^NhNi6{la z@ja#&HWAlS?SYNTSI${Y9sEt6}$l% zr(445TEXoPwFc(OXSxBY+&98XiT87%Cg99cjJKXJ6YdbhqfUD7Sy}`4KGhhXULdho z!6m8$H}(ldclis8Gwu7pq(@?K_UrEQgDdf)vl`Ih&f7ne;_@Ev)j+A7NHAK=4VLvI)(s7nmOnwU3R-{E*%U zcCOqoV(97TgmcV1H{#L_t(IjjhzpYgAVp#_{jDb0;$~uY#Z;LKod9U}+1!6$B-# zAfix2l*UbIiqI}>p%5r)T!es9#Fvcf5|B2yp-R z1$hxx@x6>nSbyTLN|oSc$d*kX5yuIh5-QaOpY7ega^*WyFT^=VVp3Z3F!yYRM-T6D zZ0Lvr7{7i;Qs-zZD3ZjIn1p;zv42mWS{9so9Ex*}D2joM8`rKd{Qb9YT`_ibLL|%h zyB2|Dv=`O_JSg*@Rxzz?Ixmk0mN&D+xw zgf&`Q6xtYkPq1l9)QD;E6~-9KVZhKgUpC+2WSZIP2BM^~QB;Nh=Dt4^xrfMUU?XX7TiS9fD=ith=|rOZBg!rb#&l!CDf zXPfWvz@b4g#xQ>AociMM5$Wjc;?Hn_wvG-?jT}{jUwtQO>Ns<1xOwFz_`v7l<$Ttz mTaPiC(Gx@O{v7^G-T>(!ckqvmw+#RQ002ovP6b4+LSTaGL{8%X diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/farming.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/farming.png index e6a28501d40c531c85fd577edfc09acb1b1a68f8..6120f2ef611dd5eed853fa72570c4817fdd5306d 100644 GIT binary patch delta 163 zcmV;U09^mU0{a1wV1I^5L_t(IjjhtL4S*mJg<*PYTUwpK321CwLsxMuwqToQo>4;# z!Mnrab>_=|1_!|XIq`=f1l(%|F9a#2b2U_57-M|UdFrt(9wsn{iE{foVDw!Z$gzx- zMBnF|FrLY>(!W$=r87-nUe^3L_t(Ijjhn34#F@H#__KLF^kwHNb2yY1&67r;Vno=`U+Kh z03?zGfkz=~mSB*e$m9~t1cu-bw~Q=hEjs7KAW$hq&N<|H z4gfI5w4&aH)>=eS1Y-V0$booDJ4tYb^laa#&$^dSc*Sy!(Rypp%d``!mY2 zM4F~w=X--X2}#BQvg;F*>AdkvFHk2TEoS4!nZ3YzSsTU%Ic02+TgC!?%6@{rWu0K3 jvQBWll;m612@aVLQJY6|Q~=aWrpiMgWDCkaKr4@s?|_gELa~UYl}rsgv%BsD{?PDgW2HAl_xqLM3iROv z+#y)}4}8+B>?)w;0AC>%hgcC2!1wJAl9RGUrq%X~{ocqjZSAgdAqK%H;-dw@H3xd-_iAgf}51Ob?pyXR#l z?I_gwj*|vy5eXE6aAA))0`-Rh1h84R=Qdu2w1^ZeXBJ@6cS}b!<$j{!2dp9m;e4df zcLSQTeGXtAXcTC@1$iGi0c2Gy=i6A<>qfT_4 diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/favourites.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/favourites.png index f2a94fcce57d9a326d6851f788e641ab631ccf6f..db3c47d5bd0762e063e25371dfa61f08171d1fb3 100644 GIT binary patch delta 881 zcmV-%1CIR53Bw1FUw;EmNklX6$InV!pKAz{C#WBX>{w8t%t%0pi%<-TYtOJQLHGjax4}q6p6dVIdu{2-> z?*Sv~hRu^TL&l<58Yl-IuK^&~Zlrb_Pb4J8%D{FXagjAQ(|*8!Emj6vqz1}*bOH=C z{BZ*iGlS<+1C{p;%;Ho#V_{%Fn2{Q&eQaWDJJR1oZ2-YkU=_#*C7=fE0K2*P7#%vP z0it@)=(ayFG=Jm!9!denEfwZPPtH%V|-$VBl!LLzwGSpDydkaMui({C~|VWCK3^1qWhnxT9ms&Z`*2 zXFy{>18B6EP9{7nx|Qy!dT8_piwIiD>H(urd|S&FH7ZEl4PJmk**bs@%Rz7c)s*SY z{dyss<@eb(0mVruxRye~^WYm81O*`#B6L)M)|?Bf&)B>9a1B)U>lwC_#OJ^SxB}9` zu7nu0Ykz%r#+3A620H^dMhUFX&GYuKCNmy}FGY0XEQQZZ+GR{SC z2!)Ei%!#NjBLu1E zdn%(eL#oOeLE9`o4dEDQ@E6GO$Rr9=VOi3gNPnkXOtZyjm2MO+JWBLpAAe)96>apI z4&^V@Cs9Lc?*t!gJ2XD)I-Lo=1a#{+|BglwyLv2HP8p#w5+9F z8EoYx4MT7erFWl;3sYgS`qYbT-~_M0cWawQDCyLSD?)K#fMuOg?n7IA&@HGNHr3@_ zPHG;Z*>GX6I2DyVx#u_9RCJ$E&Bs_FyD5>O9*C2`Z%?T`r~!0Rf<7?IFOUwfjmmSV zZ#|kRu!DBKY7}QgYF;jY1Jv``MEu{6#`4Rpmg4<$|BinH^T4kw%>vb?00000NkvXX Hu0mjfqvDw9 delta 1147 zcmV->1cdv;2g?bNUw;HvNklUuauZ9LGN=H@QjMb+ubfGuKUOH({_B5kVjP z0|wpP@*s}k9EySuKFH=64wZ}e5D}*qR-Xropt1=HafmM9m=6QlgY!YRc57!l+w8Vo z)7&hhMlazxzA)_c_1&`<*{RYt7x1_1Xd;@*trox*;1{45Kx-zYRL}ji!#=-S0FMK|Qkp%0zIJW?xwQYPnn;9FOf6}((AFBb-4;-qt&CIxZ@Y3vF+mheiQGi%7(hd9o zJX&qfH!Sc+P z1usi$O;HFOKms061VTU#I0t;3h^7__bt%9B;C*0yoqqtgD@Q5af9jd*AJhXl0$4!% zl7SVcdNW_D>i@bhMk%dsOcyR*x#H}vwChrUKG#)02Liqagjh5X0H3e9_*$3#MYX@y zkj)ku8Frlc`QlOAlJR8#0DS|Yk2Y**Io#fE2K@d-0X0o#Kx+_U!C%Xw7S5c<*yudj zY%vQQvwto5UQK{-+~^a6FE-!5=CO61K_g)L5X~ljIfyQLikY-4M*o>ZO6>s`fY)tH zUZ@FBhUf)8>5jDQ2!}(hp^zb(O@Bp7X9qTrZOOCs z{F(tc4!i>Rn+;x;b{ucw%=6P58#y%uh$SO2;2TPN!iuGo){f(SdiI4IM^+3FOGX|7 zet&BeyfU;=n`(^|f}M$I>U7fpv1FtbxK3$9s;PWVGC7q;D^1tEAzE7ebwRYo6@rb4 zXlklifIYy;rFJPbo~y_>9uwnP@_7kRG)D$HwM2 zT{)PaXa?W}uv=>a)6)fROy^0bU9?66bHF%o7C35K@-jd;Zu9_e15X1z9UbP{^<6=+ zZe0+cPcY|r3=U=9DtcUX_pYlWb4M~6?}jiAmP}N?zw5W-{{YR_J>R!Qm_`5q N002ovPDHLkV1oNL7drp| diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinAdventure.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinAdventure.png index ec3bc2cd643bf2502fac92712e718f596a4d4bf4..eb13149288fd3afbe81258d7b648a83cc287faf3 100644 GIT binary patch delta 260 zcmV+f0sH>m7`hj*zY2c<aR<52}|R%Hny^ z0V+UgBeDWa-U)vW$ZbR@TEX3~Z-pfOkg0000< KMNUMnLSTaZQFjLb delta 426 zcmV;b0agCG7v31KzY2c=iAh93RCwBA{Qv(y11VrrGb3INezpG@NimO!VSoW6p%6g# zv7#(~1Mfd3Ekp)i2oUnIlo);kpS>b2L`#=T*XC}-nKob{0ZR)k#JW@~*`Gm1KAqvmk0(T^#qAKH(*S=~#jN}coQ%u_)rp9E zGrW1Zl|d`npP(a{i1odKN*Tl7KVJx{{r>$S!<&~|8AQariSraOaZe3^ZZ6DTlA?f_ zg$IR?93tPpKcsFsfS&js-05OqU|?WavM3uaSJMP>5KImRh)t|ShX4yJKRixdU0oR% z7#J9K@7|4Kv5bFwIwEfqkx)s_1)QAn3=9km4B7^>QBpe$Jb5^ifq{X6K|!UA;mhZ% z3~yd;rG7R|R_l^Mr03AE3 UdIb9ChX4Qo07*qoM6N<$f}|(4xBvhE diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinBees.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinBees.png index 98e159d6cb0643ce044b3c8acb57aa525c60ac08..df103274c31599ad217a5cf5d0d3b60b28c1f5e7 100644 GIT binary patch delta 267 zcmV+m0rdX!7{C{>zY2c<>q$gGR9M4f`2YVu11Wf86T^Rem{ju^2E7B&Ex0rvKPJ^d zgUSrK zzUeIjBU?UaQWF>x6DsHqp*ZeA7C*dy8;pr@1Vs*j1vPRyAjN-jiW~rodl-fVJt>xx z?EskN&2=d#jvyuOsp0@+T>SuoK?xGXuX{#bZXhcPV3vc}J^vvzxl>j Rx&QzG07*qoM6LruV1kEcYH0uf delta 447 zcmV;w0YLu17xNgfzY2c=o=HSORCwC#m$6F2P!xv0D}jRG(uzYth;QKN)U8v{!L7TK zgD+6p!O$1z;48QVR5H0`a?=M8S`a!&=_nKm*CF1ty={_vQ?;#lmJ@E0d;asEKPTr3 zDJ3>`?~BYA&RSB~?6RKU<@GgXS6?0}6x!(sASUk5TM(Af_N3)syu(U|A^=YF!Bk znthmz=YdSd5U}_uru_??qAhe7LgdDn1Aqz)LjljgPxUteor$8#-;SB^yXJzl+Hd|$ pm^Q<$Iu-w)jJA(~KYu#@901<_$Fn$p5X}Gp002ovPDHLkV1kF~)nxzx diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinBlood.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinBlood.png index 1212f7dc4f1464c28d277cd4f7ec075dadc28cd0..9add9b7b55f0024cbf80e9a81a6ff70384f43be1 100644 GIT binary patch delta 439 zcmV;o0Z9I)8SEIazzTntNkl#shml2TNkGIPO@Kl3uTQS>&uflBr3O)PvGx+r!F1O>ueTCnJf&d%c=;%qm zoySj|xO5C>_u?-~0QhkP9qZAF(|+#2<+gu$c?c&{B>=1(N8jAkp`$Jy#t*Hy*n;ny z@p@cjfCpkXE}(x4Y|6DW_u` zO5r8K;sHL^;P+14Jd4jW_?XB!0&fsF9N=Jx-NoF2bt32M@IfukNBAhf`yo!%;GKHB zlEHyEAt32Pv<8k4copm;a4^PuP1qOVRJw#O;S6|@&>k=FS{hfn%J3JI{WsiEK(!;P hcE#1nXxC21e*veJF-R19#7O`E002ovPDHLkV1kKf)xH1# delta 497 zcmV#QcAq&a8s20VRl^#FYyA@S)v?);*5s}N(a2S@d5+L&E6=Uj(#yIGFQi%$I@Fc1Tkv1Kk@stvU?p z@Mp%yDX6se*XlE&UNC|X&v`!`&b}29=-h(-=`l0~6cvU-aIgSM_zOy4t$;c?1x*@8 z5-byx0Q7ajw)%es1`;j6_-}ZAB9jEW0A?PVo4^Rv*g*G^#z+qk3?gGOvPsApkhq7} z40I^48?K>&znKE6-UZPp(R0We@bU;}uPWy$cr@YIBUDeT(*;OeB(Zn)h+RS+g|sEe zVR2_d!iE>@>Rd*jY0y+Sid#q^ROA;mlTA8laRFqmnt@m+8mhJ6GnB-aQuO){aw z$pie-V0pjBcR^nSRwI(1Ko-G60pclG8+G5jY9;un#Rx2VtoQet39B_1xYfS#XF|6b n&hJ$G|7G<32>kP}i~-D0#X_zs2e;9js^o&Ma?-&4po2TPEyj#ow0000b2LX*$C4pA1c(dPaLs zA?klvo50zO^qvvfX#nQaOJ=Ex4t zp>jkcV`7XEC^`HGF7d}R-~hl$@_sttBK@9g9&jwM%zUJv_5i7Z>xYjNbPC|ThiUXX z0NYqJY!?HBJ?08hZE8f?2T+B>Xb>Fa2Al?H69rfoPC=rpzD8rr0mI|BE@CkOOyfVG z>J;EEKtwhm>_yjr>|Ib5KpjLD0MSYKeaR8HwTb|8M&Vdo4bZFwYW|ae7(`pV$c@P2 lFWA?uxGLa&8C~vmya7As27wx4uAl$_002ovPDHLkV1lBoW~2ZB delta 353 zcmV-n0iOP$7nT^XzY2c=K}keGRCwC#S6ym@KoI`S+ACBD^r1({F$&c~6n*dzB};n< zp}9jqJy0GJ3g!-reUNSJ;{MEP(1d<(gF3tO&CEAr(6%ios6GSZ2g!RIQ2ebhGXfg} zYQ)b^W`~C(jgjRsV2gPDXm?Wuh8zMIHl1eX-THR8z2;`f#2JU_B=RD8ze$V?701^{3LxgxC_I;G{0I>oeAH{zUu|TN@kVx>`Z2S-l zl)3=P3MLDb`T$adYixyRsxN_%tAaXvlPC~b00IZg@P2j#FK-{h^)45*TQWBez_cv~ z*E*e8dKbd-!W0&!d(quu`vc;i02p-yTWKEVpY`BFIEctZ8(!T#g7GVLsI(R&2OuT& z3d+FcQw|Og9y@==OE7(7KdyFEq0FdBsuv^y&}st5+`#!06_^_GVDw@wI-1IntIp*2 zBm*oyB;;$dAgtC?K|cj!W5D_agZaR5uNelNdR^ha&VbKdgeSvZga-Da|4bFS0zOpl zv_Pd)aIus07A^D|ej10JPK)-1gaAy$<1}!HPmw$LJokS9^G`3~#b^Wi+8wZ4^0;un z8t~99w9y-R0a#c|v}pF2_>v3XZ^m4x9Wy~cU-Jx*0R(6f!+PK>eMKWZmbV0l_Y|Yn zUWl9BZti;bdUs>wTs3q;_S$po%Y!?B3$%g;nv@T~vAuxX?61*ZW8`D2&$8BVECZ22 zU>9}bC_R4{SAs-F#6*hqIqn%-{ukmq<2K= hU2*zk^xvM2e*m<=^&ahJD4YNQ002ovPDHLkV1iyfFw6h| delta 796 zcmV+%1LOR=8qOQAzzTo)Nkl{d!XoSKsOzKam;_P=^`NzobmFU@D6+X zr-#VwLm*Pdi!;MJv<^=Xkr_uIA=HAFd8CYkE!6&CBxWB6wA%kp=6g?Pu`oS_XU#)+ zeJXu5zL4C|kkGi05Q{8U=IE(BQO=i-^}Ow}V=QgKQtkaSgJ?s=d~$OP%rz{;xbZMM z3b%4(Paek7#OQxWI2BuG0)u`II}5ikDLat*n(%wZDacJ@MYbN0A_ovn?XC7W4((n7 zfX&i?;`1O+`WTXAT(U20cWD2O3IPR`r5~EP>n>o^nk;M%H(j4bsD9MVnCy+d1eO61 zP9>u%Dr4hblwa(zjrNgQ+s-{lE{&}=2JJGE7=u9sV9bAp_4yf;?^}i2tI%t8VfUod z)Y3!C`(8YLh3>9?e3)@PIYk;TXc2G3W)f=l@Z|u0B|t@SJ|zdsh>K5T)MjRQ&`e|N zAP*Y$gQbY#dDm%>CpalQr%K!sJ3SzYV3lNQYI`UuJHtTdV>}ZMbOAr9DRXGEH~{!0 zzhwKON(_H2!zA2_T>ytKWV15IfYm<1@dK+lccq?=&Tcw-oK#h}BZ*Ka-ax@ivK|sh zCV(2d0EV5D#K-AydlVYmY#34#dHiaCR*M6>(+$8j!Nk$?o4Nhr7@v8{P0=)U4rntu zSO;i*`_3%kba^ml>-pF}%DCH4x*>_CF6k$>_dI_E6))GslCU}<_%4_d2l|FwG`87L z1F&pSDrykI9o*qk-9GjtTxFYJiftEYL4cnO!AWQDkKevq8hKpuCz8YhHVC_LBhfCt ziS1nwYQU)YdClc->m#fcCUD~*Lm=W%3aJTyR}oFM_Oo9ThSG4+s^b4IqrVSr1xU;%dkK8H}v0U%3Y z7J)49>QVS#RV|8PIXa)JApr9E>a`kROF)hQ@j;G&g$A~e!0CSga)KUaIf#Z?3JQt9 zI6;Ex0o@^F$34jMhKZUe=>QfTATeAHp{fHwG|1A_baAjF(n}TL4x(8IAX^@hD)zsw zQ4@?|j=+}=sOA8e&tVojcnQEAqH4+s#xw~5yGRkR;h>;~Sx&6Q6gvRqYmfy-9s>WR z)!8vD2C>O05eZ;A0Aw*JwZpO;$Z{1^ZVVs8_#|gTLIn}XVwmNyASWiMsa6z&EQ49@ z6DC2H6g_2 delta 609 zcmV-n0-pVy7?c{YzY2c>KS@MERCwC#m)~nrVHn3hXU7O3Yt7Mi4hrky#HOu9H*FIl z0xtqdh;u#2WNhkA}$ zv*@{f-}iZ*?+ZJjWa)5l2vG0+aN ze5Q56{6~F^961AqW(PIo?GQIcv-^!q^q&W6+INE7yR6`uOKI{(jft8Ux?-T9IEhxK z4>Y1TbT{B#R_cY4i4yP9A27;0hgi_sj6rV$p1BkS#YtpCWHngC;T~neX5#tNH$*Gb z#QeqjJxw0)KSF=E_L1^9tHJNgx>$-)NK#FiEgTrm+Z9(A9-HRj>CCw5HbmIKP zMh@GgmBlA6cu)I?BiiBWivdNghIy(Op=#1O>&3n%=`?K29)@2SAdC@CCE@ zf?006#&Dgt^lljaTKGk13wt@ol4pv0_g`Z?X*h&6?5F?SLQ;!)Z~TDHy+q$~C+u`1 v(yD#`?}W{ExNf)N|39O@kAZ*wcl=`jy7vzsSLx#|00000NkvXXu0mjf_kcID diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinFlower.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinFlower.png index ce3c23a765836b09c97a85ba05ca66097758f9d0..4b30e3ad1e33111bade46ec351f5abbe9fb95411 100644 GIT binary patch delta 271 zcmV+q0r38b2apD^vjLOE0Zfy!0TX}eNklJB?*M9BOtM2p9YCrBK7amV$1(TMFG0{|^( VW&oxgg{uGn002ovPDHLkV1nqeap3>} delta 406 zcmV;H0crk_28jo-vjGnVVoOIv0OA1R0OC(Is9KY-0Z)GcVo5|nR9M4fWFQf2Y-0G2 zPu{32aFp}zHMOpmn?>{CjL>KSJ@c#2#IQ#kACveN(J^P3vN7E?y_2xf= z+fhCSNnsgCj`;bV;p>mj47;p9(Z>Nletl<V$1(a;NlVc$Cj0Ep6(=n!Q}yZ`_I07*qoM6N<$f~Um8 A@&Et; diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinForestry.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinForestry.png index feb94681a24c6da992b414853881dff895cd3d4b..3bc81b8a126cdc147ee0a2611949a41b541f4e9c 100644 GIT binary patch delta 358 zcmV-s0h#`u8k-ofzY2c=MoC0LR9M69mp=-^Fcijfgbpqu=;o-@O&s(9P6`&>9GrFN zE_eZt;0YWYyol%U4v{bTNeFG4q%9Wg@OU)Pe!rLZtPRHpymR&3c3O{AE2yoa+?Q%cmY5pO9*3&%UFL#tEgUp;bEYJbQnG( zpLWyw03Zf|!M^*glvOV$9l4$NRpiY=E`V$AA$DAklmJDL0R>?|AZ)Xc1>$W!KtP0I z6epD4mP!HeVTx>KJtb_KGQ^BtEkH)q=_XczF?s^Cz_!%Z0tlu_{52h5AV>oO3S+iC zp;QY{Eh}Y9Xg*%OMaX$R2m;W1Yc4?=(tO8tIXVI8#$x6w030@`(6b@Nl8RORCwC#m%VFRQ5eR5iUcwBVCVky}iO1F&GK$b$)Ar-yEFAPD3T*FxcVdN-=(2b3<(D zJD!jCJn!>7hw~mozu!koe2y9>Zg?8$8?@vza?N3w#=vmJ?mK^z6Beu57+E|9rd8~` zH96sNLmMO4&VXs$gj)Huiicy|`e7y(&jYIV^Hv`228fxHQ@x=wp?bln^^kBkFmk+J zk@4&}^z*=|`1YlQ)8zm!10eN^Ov0Nah#$f30}eC+Flwp(S<6ZBuz_dCLCl<_UXe+s z%4|k%;{5cB!cl)sGYh6!wXauXZnye0`<=m9I#oun`zTmzv`*Rp2=_*_Fq~ICcV-C^ z-VAtw_Ybh!mf4IH5d5nYj+DdqT|LB*Ot^cWVBW8+*V6;xZh*br3}PtDi`OgItQK+` zOMsjBx%*W!rc-4Fteybs6&W!kvz=Ju?n)PcuN7JGgyerl1W5CR9M69m)~nrVHn2`5n0g6jSX9^VmYx`5eRb-YDTkZ z&YQ@2EI0DU7|6CV5d+P_pH;+15q77QE@w3;%-thi|?wG^SIh=bU0t z7Y`hs_wal^&-1>#oWlTMdWp|r2A!hUdd#sGXa@Yqb&g(zj-P+PQNW*H+sDZh3{Hto z_ar2k00A#8Eki0DYmne9&`rk&;mNmj^DNtPD|ic#qJdXFOxHV=NF>l`G?;&xnW2*)2eVi#V*Z)4?P264 zK#D$k%;L+|78Vy5>+@vl7m<`oxZQ3I6xr|IEgYlcUdWN?Y=;k6Kpp}(n?CyR; zI-SPA&@k`LyS@nt=xr!K_dJzKL4IRgkj}djAfQ>R4TX&jBoav&4bz<9oCFBy$k0`#exa^|1J%DuoGND6-Jug(A3hla?LF@Iny0(CwnoIu=Vw+D`J( zBzkC*ttDlLon2)tGhZhO_<{f1bKduPpXdKP?}uVp7Ix~pkCcCs0|ri6ik1}HXNjlsmB@L)Q44dQY-e_M zmPjOms;V?JG~o03FijKFG_fpbcDs=pdB&{B1LZ0{okeO<0)YTdr<0bJ7F1QGqoV`U zG*J`


ZrQzO6LxJkFa@FHsRKzusO&ERh&lS$Ur)<}OO5`@EHyk0L-N<1D9E|-h_ z`(B{6wY6Y66nzZay)V=br_)K-o=)6uH*IZgNGWkR90Y?wMn*>X@~f}W^~(=b$a$eI zDR}#>WAyawWqy91bUIBUksun4vcA5~(9jT*m!{D5%XzV^OADkX=s!BhbG`d`Z2NYS z$t1B@j7)zfgAjt|=4Mt_R+zl-O+oOQQ_w#!$eHmmW@csxFD}y9B#1;~csw3@dwcOo zNnhXLqTp3~Kx%>$?;K}mXBXz(yL|k~r_2X$JOGlKz|-pG&p%Rs0e^HqP^)47=BS@1 zp4vewm15%D7kS{hbQA)wc`KHh;J`}F*z4d3lKwCqLv)X4MvW)n|d!1n<3joX4Ns zK{y=Zv(L}k2Cv!!QWFen!#usSlT13z)hjy7ON(^_FS!7z35JJX;mr6L*1db2pS;Kq zKmJ!#SMZW|!k5Pd3JP+oWMgB4)z#``FV_2tQea^bi^Xik%5D{1z_;&b^X`T@Cgpa@ p+<)cng8#pa{yhr(=U>P72LKHrg@c$r8d?AV002ovPDHLkV1myttu_Dv diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinSpace.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinSpace.png index 17155bc02fbebc430ba69efc1bab2ef30b5cebfd..a75994c058fc17964c23636e036968d28ee41a62 100644 GIT binary patch delta 214 zcmV;{04e|P7mOFMzY2cm7j(JB7!8#1V}}?9yBiy1GbrtRH!|H6mVbZNQK%J-~zcq?F(3e0q#kO zm7ZuQUM$sL} zg=Yy^RR1WzX++o7sufUo!T=8mz)u9Ou-wZh640ErSfKxi`meZ8M!%hoPyKSaVY8z* Ql>h($07*qoM6N<$fb2LYQ4OmFP(gF*$e1dNAUvY5;=9e$YPXpvy3M?6f?hkiD5aV zj$t9zVsy)>6$&yq+k}+13kb#i;BOP+YQs_5Djw|_4ZRQ;_Pt}k0479LR49Le z(7{p>u>in@G3Kr@{#;!(@dO;)*mne^z4rtBKpgIBEI^5f1#nicDFNyWd|zN`x04CB zyLQ1(bHN3kcFB!J6QBa4w;;Iyb^1|=1*8Yjv7nZqCt-4dPx#07*qoM6N<$f+XN#b^rhX delta 343 zcmV-d0jU0z7mOINzY2c=H%UZ6RCwBA{Qv(y11VrrGb3INezpG@NimO!VSoW6p%6g# zv7#(~1Mfd3Ekp)i2oUnIlo);kpS>b2LctdD0F)@Z$uU=tQgDj`PugP#^*>&>M06u>pCI$%}m}M|NIbh&( z0kLt9>}wbs-RH=13_tPb4w$_}M**&Q$E8k)UwDW_0kH}nRQ_UMU|?W))6T#kk_-_u zn=8Y>z`($8D)|XQt`Z{WF-@Pk4uDzqis2OlLpy4^P-tgEq?Nf4F(C#TMFDccL(YcC ziImv%GPKeFE?-ZP;#;f^fR)MU?Ev(AtHG~Hle%E&L;*1s%aE)KaJC7l)h@sl_k%wh p;%dWD+A1FH84bM<81}tmzyNQvk+JOhk$C_B002ovPDHLkV1jB$l}`Ww diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinTechnician.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/itemCoinTechnician.png index efcbd29df787155dd5cc51e810bfb0d867dcc701..06f0aec75afd36a06d08ed865a39b0162824697d 100644 GIT binary patch delta 524 zcmV+n0`vXx8owE^zY2c=>PbXFR9M69m(fZBK@^7fQOs>+*R?hAPKrzmEJTWm>RE!I zB2%Ke$bv`^BZw%9qV%S_y6Gyi*XSKiJG0I*tvfq2vV~9=2ZoXJ|KB-t7-tm#P-Nn6 zQ-Pq6)l&u@z-!QH1cxlp-~sRqKOdb)t+sHCF5g3P>Bilc1(JUPAf^O>m|Kh2crP(` z4rZwt4gjlSZ{^m)6^zVZxaRR<9gNwNo{oeEu=2n)H)f9I0a(U#c-zi1r-KC|1i-4C z{Ep1y#Zzpq7Y-pdy>G`}xBx7365q_Hc0tQm!vpX;b1wj0xt6cM@MKvGK;-OM1LtpE zwavFd&29r|Evh)ac@Fe z1XVzUXpx$#GArlh317uXq}^>_Q03lW+3~?M2>vUoEIdo?_zS~x>4QWU!@2+f O002ovPDBK*LSTZjf%KaI delta 703 zcmV;w0zm!08SxshzY2c>oJmAMRCwC#m(ObxQ4q(!EAdazL!hATMWGiFa|pH+CD$Nc zq=!<4KxwU@m{_c)2TM_;l|l|Zv=?#jQV&6dVr`@pycD725NN=lLjQp#`(wsKcVG8+ z-fk-u>AUQ*$;@}=Gc)h)D$I;H>%*)PX^=0o635>eobXb*5%7Oze6c6mVY3yF$iGLR zTgK`02iKfh1pqJ^U^1|F_cj3F*Iqm#u?UQQstRGJI5PnNhL%+fzkho?1nkVc8T-V^ zw1P0LdmT(BYWK%nL~IgX0;$+VV*)cpii6Gg1i~_RuAEwRVP{hh6t7KA_-w;SND;`X zRV#Bh_Roc30Kk9X(h2|u*aWkQ?BW{$jLnCSk8dOLVzXppHN1VVsn^C$4WW||uWM0ikk6}uF{B=vfBW~S`5|Muy*dvLj;OATxt>;(pW$d2F zur@j26W=O66XM^V&I!9j1b#2v023iyS_kd#L$f-%@}mOH-nxZ2iIH19`&D$m({6jJ z9~v_n)-PTB!DliG!zhI5yV6Dw4%KqxR& zsC4zY2c=c}YY;RCwC#SG`KaKoI_BB3GsfghQ|}prTj@R1}}UHwmaH zR#rCl_a?r8{dHo07J`M4DsWY@W3_5>`P)s-i{g~~Ge6%qGdoKn0uy<-quL8+w?ZcR z7%LWPLZBG&=0?53msc}HhKE2?#Or>&!nb!bL{^T#TGfV*yeWU;qEwwPA~C!i(A>9; z{PboYM1;rt=T?SvZfGQQE?6OOa=ixt$g&K_SG%1Mu%+Wt8_d6Q*5B8 zndbk_blv|{aiOP~*8dDYo&Oq&>Ttu(TzmGPECXRK(@@j^8^9{(&IB@S%f9pfXYTp* zpCki8hCy7Wf#MpVp{yVSNpc~&%a9CXCOHf}&9tE|)5M4XkZPAnGSJNgihhf;vvaKw$^M9ZRqLM-Bq4hN+2j{^w@r_)jQ&(IW)IKvAG! r>JlKs*#A={FN0jg&B5`1P?a_S^jd&+LV0)p00000NkvXXu0mjfoHlgV delta 373 zcmV-*0gC>}0?PxCUw;8sNkl_y@setK3h5+F8rGewS!vXZyps8!LxjF;kVSgWgE;RKRsY(F(LL1yJ zF#x#XRf;by^kCm$w=8?v2Ddp2sz%`2%64kCIx5~GQc0Ql22EWfRS}Rce1O}$R})kX z@%-$>-A=6dFB~rG!vwc%b%wv62%7pbsR~2B&;hrL0|NwABjA=T&o{WWrcp93ewP(T z)&#x=*)Vnmw{C2Cr&sTkO3G|37?mYjkImz;9zyAm<&DsET4S+(w11G1C(p?eMZyfv4G&GnnTY*#17J8L5g5>HO)m2dPUAiSY*@76 Trws>z00000NkvXXu0mjfnI@}^ diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/misc.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/misc.png index 14139828caab8ddf4dced199db4227d17e0bc3b1..784576be39ab7b2396ebc4e252293130b36cef41 100644 GIT binary patch delta 156 zcmV;N0Av5H0`vipV1Iu}L_t(I%bnE04L~6X15j7&@(jTe{U;J)_)t7>QGBUJJtU7( z?oM~-)VIPERL0DVW;UV{l)(ud6IEb`w$Ow|l^_5K$zuQrfWHY9GLr@J3@{1;?Cp57mULmog=Mddpi#`W!Y;)D;J{zS1j0I~JD!0000< KMNUMnLSTYS#6U3s delta 213 zcmV;`04o3V0j&a%V1KwtL_t(Ijg`<#5yc=3h2c{VAObrzQ4v{31SV>Xdf=`OlhW|G z+3}cfemH8a*qKsF1%MdiF}ru{fW$a6bO{oBo(BLBLYSgM&_W@E2CmQ#*cTD7>lxZW z59)!@SxTv)4Lr}Ys_GK4dm;h=xbOQ5mQw0Vd?z3q=GuX8`X% zC6IIeztENvQq}#!9%Tg~uh2p+IQmPk(8FAi=&W#r4MAJF3oSvSyAbCGAQs-?>)Idq P00000NkvXXu0mjfsMTF+ diff --git a/src/main/resources/assets/vendingmachine/textures/gui/icons/raw.png b/src/main/resources/assets/vendingmachine/textures/gui/icons/raw.png index 5c7fe4c84ef983676230d597d2695895a85b050d..029a7981ad49d3ea9228f692b74b2a5341c34b25 100644 GIT binary patch delta 661 zcmV;G0&4xL2I&QmV1IN;L_t(I%dOH|Oj2IRQa5#`a+>4fiqRn-2wOlW?9WtHhP0+qt~4jTmD}l!G9{6?Vfd6WDdMw8r7D` z4aYdU^PfP1l?&|5Ps8mM2!k`=nJEZ8aY&rrA1=zb>#xD8iNIRESyy5n>PQAh18JOa z$8d&C;`jxIBk1legDq_0?ZK&OGz6y$?f9V#yG2_2!%#-C3JQL+DAnw z33fUCpE@pO(SI18g)){!vvm?Jq^b7S3giT=vygW(RRorKe7N~x97}5sPHU8*DA-R0 z-dhMDx6(LGTFGLwXp7IIp0v#)VsE_Aw3R%cax!@QtoGpMA(s5VikrlV*e+pe{`5zSeUdOixnMJX%`YIM7spzIf7(^3e! zr*qVU4w4}@1vQg|gh`-=j-kp(;gD$p3$G?{b=3v?vJ$HE0wh+A(7B{g^wp!(9qvs( zcqZx@n}7N&9HyZ*yP>f$$b1~&oc9J1c&WueNP+w^ZoCNNtg#7$-ZoCzD=H3_N~ckR z<*y7}bG;Z_)FJ!C56!R?2Co7wdOk`X_Mh2TS5}dq(>Z2`hO{D+b6oC+-XSN=+Bu1? vruf-xHLU~9P#ee+`h<|`PnJIH?aVK%R!wErj1Jd200000NkvXXu0mjfrr<$$ delta 726 zcmV;{0xA9J1*!&+V1KnqL_t(Ijjht%OH*+G#_{L(+d12OnVxNKnzm5F3MwiHBJZ^H zLWsH%>Y|{cF7h&jic}(SWkPsS(M1`gg@m*~hfarPi{8Tv&G7wgIbC|(cD6as+4*%N zg{Yw6_Ye5oJP%=vVJjnRfexo<+k^I2?;H?6rsoa!?3IiE4SzbE9--Fl^6N5oaI;Dr z%Jc*)O4RZ-cPitX1|3e1zS`X$*nK!pJ2W;sA64!FShB7_xNmj|33%s%U=t?jN{(nUsb$SAYR9nJnbAuRmN{}YvIB~uJO?53uvzq1U;d#FKdDm)iy-KbWvNLz{ z@Ud|OM5|&~&K|VA@E|FjgLlXeSN-ReqpVlPQBNZHKCp#Hu1ebJ_!Q4SbwnQSpX7a$ zJ|rY3$YX;Oe0#%})wkJbCokqRrm9ex3R#iSR{wGBV{c`D0J11w@S&Ec0MwxUON;}4ALIM~<1pVhsGhTwIsnCRpwHd|@qb*n zC4&P+{nvwhzkuTX)O5gq0_yXS)qmW_3(~WH2s;3X(Sw=p4u2pC4~PR!@>xMG2H~{> z;edU}mVVgF`wEmBKsYa)o&FAh7DV%b*dB`Y2f_jM)Gvzh6wB}S@V)_A48owGr@I57 zmV$!49*XS;!U6W=m_@Dw&VtH$P&NZ$XlkdU10W@2KPZbKVf_)*Cd6!>h0@yrD2Z@# z3Fj^PM!_J+1tA!0~TIYb+6SW9lR!=wQKWBt{Jjn=lzf zqJvpP4JOr5&0-L0Y7m3OawNEw(4If-@w@98T*VEv^!$#bZ+q`v?tPNq?_SPlSr%S~ zuLh_Xa2PxWS}W+>B%+P~2H*~8D%W;;QOpj_=+lZS);$3noPU}`W6$%7Dq__G-iDSU z2-KB(p<#k)QfLUE1D8a!&T0UThvDIT4ru(WJvva&>{#GE&+CYek^G9HifOk1D5~&% z(LV_+mD2ksi|)}vT2V#+KLr5ckl)cD9q_I21aKJa0lMt07Z{Wc*ahAPXph!SJSAEH zuCo@~8B;F6UVlUhAYqqsiYiWI16$DlBbAQMa4UX%1UP@s zCWvS$nE=NnjHkr;@`f0ecLaanEASWqghT#4pzlLTE*rqDr~zt#S2GV>&=J=j2><{9 M07*qoM6N<$f^Esa!~g&Q diff --git a/src/main/resources/assets/vendingmachine/textures/gui/nei.png b/src/main/resources/assets/vendingmachine/textures/gui/nei.png index bf64099b320ec883d2f8e35c8bb70c402a52e54e..15186a304f3c3e8908f912ca2e909824d6319cc9 100644 GIT binary patch delta 944 zcmX@E{9k6nJ+6A@Zci7-kcwMx?;gxOWFXRzcssRa6Sqe81`eTQ1Fmd_+Zz}Hz6UJ) z)^ufpK;!-Ip3|yMJ@oupxG3q=!-5slzGkhyHfzoE^^+PlurRPN2rxJ>G$b%atiRrT zy>5U0H>+gB=b6vWFk3fV%`(l%HJiO`y|GyFytH$Flo_^$1v6MP)H^URFamXESTb0q zg9M;_kV#+(0fq-}nG1f~eVcIgQ|Ym!bC=J|oX2?MZCU2V2%f0hZ@1li-E(x#@|ni` zHcS>Pk99iuv3%kKy5m>T3RNZrrnUx#4hD_}4lw1QZ2onxDia5TQUk+>)vv9bADA-N zKUjY7*Zni!r_G+f{SISCgMVEU+k>K=Gn!`0zh@};tjw_EXQwd3`Tu!!OzaQ7oo?`3 zRj4#UxKW91!5t`VK~m`R8AHGbp4ncxk>&HZ$hzkZ3sn(`M?U zScMiIhjW%c(-Syk81Az-EMVO6_aWSpUF*D$KQ8=`^%WAvKJ(of6u$8>a7Z!iX4t?C zjSFZ9!h;f%0SkYm@Wxc+fQSril7wx+rVAog&%hzn@U&>A?(3`5qA!DD4x3uI4R|Ht psz_h}{ZDl>Nik9b!^du)cxzH-O%J#KeVqXaJYD@<);T3K0RS5`<#+%9 delta 1790 zcmew_b6k1DJ+6AT%bqTdAr*7p-i^%*4wq=VSgWv8ZxIjM5fdB1CdX7h9@V9bls!K1 zAGX@NV$wFPt>(U8zcuHtW!&Qwt=|9U$UU9oj|*i3&UB0GPy7G-{)K}|3?V8El1vVs zOcN9trl2yvGgf?kb+!4p+3d4B_U-$pS01;ozUJqHxrTE-@0`24SgfIEKTE>qn>HCa zyYKcrKR>^Iy7hef`nn6pWS`emJ%2ZcRUz3@hVS(z9l0~c)=U#_3O494&bTAkaHfwT zh4a7@AX&zu;LV^`&Z4kcnIV$NV5c&}Oj*VgpTZkX0;x9~4$~NX-f=jjxif5HNhoq> zFtV;^nxM)snH0l>FwJ_$Twoz{tZaAfhX=pEzu$j)?td+Yb3aWOPZTL%c+w}`Xk?wo za_W;2F){m&eGcZ4aG z9t_8RC?hlhT{5#CXk(G?k0*Wi89{-U4GLe0@7`ry>)~%DX*>>{^OisFS)3m#J+wH2poQMV*b&n~fY!B0k zsBgdj?$YUIm;*Ey6yLh-f9qtK3d%r{$TZ>U#j5h zu-w7z=}x uFoIK$!lOT@9^FB7c0w7JFrlgw>X>tu{_L21rXi962s~Z=T-G@yGywn@9%!Nf diff --git a/src/main/resources/assets/vendingmachine/textures/gui/nei_header.png b/src/main/resources/assets/vendingmachine/textures/gui/nei_header.png index 963b277efc2ff01ad69c67a1fd87380fd626194c..474cb19fd70463d421bb9f50b99810000660c47a 100644 GIT binary patch delta 51 zcmZo?Y+{@crX%j@;uxYaF*!kj`H#9(PnN`0g9}m~Obo*Io|pYidF&a0z|+;wWt~$( F699&^4ygbD delta 56 zcmZo-Y-gMhW+>z7;uvD#pRBFVdQ I&MBb@0P8amw*UYD diff --git a/src/main/resources/assets/vendingmachine/textures/gui/overlay/coinEject.png b/src/main/resources/assets/vendingmachine/textures/gui/overlay/coinEject.png index ab26b18a7f6b7cd552518296086fc825fd1fb884..a4e157ee84535a29f53695347d277483097dfaa4 100644 GIT binary patch delta 308 zcmV-40n7fM2cQP9_5pttNklCdEO6 z(*cAme6tllCdEO6+X2K{NUVcs;s8ZShW{$kRB`~RJ`Zt#H~@qjlgSGSvK^o-g|Hlk zgY4+!0Bn}SaDXk19e~SXWNe~Aq63KaIkF{6QV=n9SqLA*_O^dQ$m=Q*7ZOA}06Ex| zp{f4W7KZ;iiV!gn8{Lt<)>L!=vcc!)BOCy746*~z)y}P;k^_{WA#iL4s<@T{A_~wQ zY^+Yj5FnH;$SoNub^t622E+lcp-}_N5%hNeFySdtBMK;~1xZN*RILkOSXGAMzoz^E zIzUSvcXp$>170j_!k^zscEFHq5z*8EBezvN+A|tay<-4m)DKv?H&E070000D8_5pvCNkl=h8X?U@kZmwI5%3at~@xfK$Q2h&_Mc`Nch`y#cDQQ$eRF zkb(pXh@~NpPT-plg4>k>kT~vJnu#IPuvYL?aTA$U?3512B)>Ou@oT0D!3s2mz zOy=S3L*4>2xW5-J4+H8zy{Ofi0d@%#5MP$Jpd|o-d^kbwh~@)?1PK1v0Tn+GFV8@r zzXd9ZEOdq7`nW}a^r06&0yLI83=cK`s$0S{;MkHMo4noj@#002ov JPDHLkV1nqeB?$lk diff --git a/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_tile.png b/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_tile.png index 426e54fd832ed051320122c44661b4d207a3cf32..0b06ee190dae49553e7cecb9708d11b04f75b2f4 100644 GIT binary patch delta 99 zcmV-p0G$8j1knVr_5oW)Nkl32bfId=NB+Wt@Qu^002ovPDHLk FV1l2wC2Ifx delta 119 zcmV--0Eqw51my&<_5p8NNkl}-tK1{9y?xTeU48JGV0Z4l8 zLqj5-6bBH*l=z&cA%Ny{5ZzCX1ISJTgv_9c1JH5<%;)j+bbv`cDL$u~1CV?^ABfKr z>vL*40NLmE6xRh5Iv^j)$A$H2?EtFO1q17V(FVz=14bP%;v4_~W;MOb7o)%d00000 LNkvXXu0mjfIr>}0 delta 273 zcmV+s0q*|31^orE_5pwLNklzXo z0B1Hc01W^`T0OadU@-u*$vFUnjWggSHvn4F>b@4Rc@2bmL;-kTLxmxEqx6lOhBmi--@IC4S!V$kN^pAIN%GC X!5`4u){ck(000R9NkvXXu0mjf{tOZb&yAD7hVqDU3h)(p z1Wyg1LFqh%HQ$jSr+C`}bfqSQM-FER=sXn_(*pRc?nRF{wTpO#XJRapXTxf>YuO*6eVy2rW;wVmsJ_h00000NkvXX Hu0mjfD)m`# delta 251 zcmViF?+ABp-&?e}SB8fI>JyOu7O_s0Z zI8KY(hz)}MfsTv|H&@U3xXduEHM)G52Y7%73=*(dt{Oux=Mx(?z!cASB>+Gc1pwe4 zj~oY>;HH53d>Tmr01pHJpe!gmjfJCtDtMDqQ1ZG;GoM7ciFA9ud24aM0rpA(`i3#e zx$Z;M=T(BH`7H@ri~9|*A+s%AC&npHDY|CnR|Z;j8uPb{-2m7SbJ&ES6-%iA0NEk@ zxY#X#4H>WL@MXvEi`@j+kY9@32K@8!01xOK@Bqnw570&sEI9xG002ovPDHLkV1oJ( BZYTf% diff --git a/src/main/resources/assets/vendingmachine/textures/gui/tabs_left.png b/src/main/resources/assets/vendingmachine/textures/gui/tabs_left.png index 9e5b665373066bd798a762a156320dd830c46589..ba713ee7e04058abce7b364b56e8bbf74c1ef909 100644 GIT binary patch delta 145 zcmV;C0B-;E7?>E47zqRe0002M04!j!A$tpaXGugsR7l6|ld%baP!t0baDnIs;sm7FG7P`%DvxVOXueW&uX2fjU7YsDNka=Nq+X&ccwE(|@U#M4?j?tXs3+Tk!3ebi< o0b1G@AOH#w00kiM?YnW#KXpGXMh=#S@Bjb+07*qoM6N<$g5(Tmx&QzG diff --git a/src/main/resources/assets/vendingmachine/textures/items/placeholder.png b/src/main/resources/assets/vendingmachine/textures/items/placeholder.png index 06caf894d1adbad9f6f4b3e4cd91722300ba84dc..98ec8aeac421b2c29e3c29c06ceb2329563c95bc 100644 GIT binary patch delta 239 zcmVU$ delta 353 zcmV-n0iOQE7qu9$-U@#KK}keGR5*>LlCe_4KoEw%3ue+d!y`y1B{Ufdp+%^D1JTaL z4*GO9mWr=ni72JgK!u%j@(7u+$;4zW;NU`X&Nyy$v$y;0&i}6x5&jcOL||UllretT z{k3CW9s%nbKU7;lD&QypUhu)oNW>LucDa1Va~c*YMqMa{bAZIRHt z{8|I56*qktc Date: Fri, 20 Mar 2026 18:10:27 +0800 Subject: [PATCH 159/160] Show trades which share a cooldown. --- .../blocks/gui/MTEVendingMachineGui.java | 23 +++++++++++++++++-- .../blocks/gui/TradeItemDisplayWidget.java | 6 +++++ .../blocks/gui/TradeMainPanel.java | 14 +++++++++++ .../assets/vendingmachine/lang/en_US.lang | 1 + 4 files changed, 42 insertions(+), 2 deletions(-) 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 4f3e5fb..277b4dd 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -49,6 +49,7 @@ import com.cubefury.vendingmachine.trade.FavouritesTracker; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; +import com.cubefury.vendingmachine.trade.TradeGroup; import com.cubefury.vendingmachine.trade.TradeManager; import com.cubefury.vendingmachine.util.BigItemStack; import com.cubefury.vendingmachine.util.Translator; @@ -67,8 +68,8 @@ public class MTEVendingMachineGui extends MTEMultiBlockBaseGui { private boolean ejectItems = false; private boolean ejectCoins = false; private final Map ejectSingleCoin = new HashMap<>(); - private final Map> displayedTradesTiles = new HashMap<>(); - private final Map> displayedTradesList = new HashMap<>(); + public final Map> displayedTradesTiles = new HashMap<>(); + public final Map> displayedTradesList = new HashMap<>(); private final List tradeCategories = new ArrayList<>(); private final List inputSlots = new ArrayList<>(); @@ -254,6 +255,10 @@ public IWidget createCategoryTabs(PagedWidget.Controller tabController) { return tabColumn; } + public TradeCategory getActiveTradeCategory() { + return this.tradeCategories.get(this.tabController.getActivePageIndex()); + } + // why is the original method private lmao private IWidget createTitleTextStyle(String title) { return new SingleChildWidget<>().coverChildren() @@ -493,6 +498,20 @@ private void constructTradeTooltip(RichTooltip builder, TradeItemDisplay cur) { builder.emptyLine(); } + TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(cur.tgID); + if ( + tg != null && tg.getTrades() + .size() > 1 + ) { + builder.addLine( + IKey.str( + Translator.translate( + "vendingmachine.gui.shared_trades_tooltip", + tg.getTrades() + .size() - 1))); + } + builder.emptyLine(); + builder.addLine( IKey.str(Translator.translate("vendingmachine.gui.trade_hint")) .style(IKey.GRAY)); diff --git a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index f001d8e..acf10f7 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java @@ -95,6 +95,9 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { if (this.display.tradeableNow) { GuiDraw.drawBorderInsideLTRB(1, 1, 45, 23, 2, 0x883CFF00); } + if (this.display.tgID.equals(this.rootPanel.currentSelected)) { + GuiDraw.drawBorderInsideLTRB(1, 1, 45, 23, 1, 0xAA039BE5); + } if (!this.checkVmActive() || this.display.hasCooldown || !this.display.enabled) { GuiDraw.drawRoundedRect( 1, @@ -131,6 +134,9 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { 3, MTEVendingMachineGui.LIST_ITEM_HEIGHT - 3, this.display.tradeableNow ? 0x883CFF00 : 0x88333333); + if (this.display.tgID.equals(this.rootPanel.currentSelected)) { + GuiDraw.drawRect(1, 1, 2, MTEVendingMachineGui.LIST_ITEM_HEIGHT - 3, 0xAA039BE5); + } if (!this.checkVmActive() || this.display.hasCooldown || !this.display.enabled) { GuiDraw.drawRect( 1, 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 0c86b34..6d1908e 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeMainPanel.java @@ -39,6 +39,7 @@ public class TradeMainPanel extends ModularPanel { private final PosGuiData guiData; private EntityPlayer player = null; private int ticksOpen = 0; + public UUID currentSelected = null; public TradeMainPanel(@NotNull String name, MTEVendingMachineGui gui, PosGuiData guiData, PanelSyncManager syncManager) { @@ -129,6 +130,19 @@ public void onUpdate() { MTEVendingMachineGui.resetForceRefresh(); TradeManager.INSTANCE.hasCurrencyUpdate = false; } + TradeCategory activeCategory = gui.getActiveTradeCategory(); + Map> displayedTrades = VMConfig.gui.display_type == DisplayType.TILE + ? gui.displayedTradesTiles + : gui.displayedTradesList; + + this.currentSelected = null; + for (TradeItemDisplayWidget display : displayedTrades.get(activeCategory)) { + if (display.isBelowMouse()) { + this.currentSelected = display.getDisplay().tgID; + break; + } + } + this.ticksOpen += 1; } diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index bc0f5d4..089a342 100644 --- a/src/main/resources/assets/vendingmachine/lang/en_US.lang +++ b/src/main/resources/assets/vendingmachine/lang/en_US.lang @@ -19,6 +19,7 @@ vendingmachine.gui.required_inputs=Requires: vendingmachine.gui.nc_inputs=Requires (Not Consumed): vendingmachine.gui.alternative_oredict=Accepts Oredict: vendingmachine.gui.nc_inputs_overlay_color=FDD835 +vendingmachine.gui.shared_trades_tooltip=Shares cooldown with %s other trade(s) vendingmachine.gui.trade_hint=Shift-Click to Purchase vendingmachine.gui.favourite_hint=Ctrl-Click to Toggle as Favourite vendingmachine.gui.display_mode=Display: From 1b3bddddb0564f68bf1fc6438b717a7de3cbf764 Mon Sep 17 00:00:00 2001 From: cubefury Date: Fri, 20 Mar 2026 18:11:24 +0800 Subject: [PATCH 160/160] update deps --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index c84b438..8846c55 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -40,7 +40,7 @@ dependencies { implementation("com.github.GTNewHorizons:ModularUI2:2.3.39-1.7.10:dev") implementation("com.github.GTNewHorizons:StructureLib:1.4.28:dev") - implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.360:dev") + implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.52.375:dev") } // deps may transitively add Baubles, so we replace it