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 diff --git a/dependencies.gradle b/dependencies.gradle index d4a2fbb..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.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.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.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") } // 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.2-GTNH")) .withClassifier("dev") .because("Baubles-Expanded replaces Baubles") }) diff --git a/settings.gradle.kts b/settings.gradle.kts index cbf0d00..76ee14e 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.44") } diff --git a/src/main/java/com/cubefury/vendingmachine/Config.java b/src/main/java/com/cubefury/vendingmachine/Config.java index 8972650..a208507 100644 --- a/src/main/java/com/cubefury/vendingmachine/Config.java +++ b/src/main/java/com/cubefury/vendingmachine/Config.java @@ -4,15 +4,22 @@ import net.minecraftforge.common.config.Configuration; +import com.cubefury.vendingmachine.blocks.gui.MTEVendingMachineGui; +import com.cubefury.vendingmachine.blocks.gui.TradeItemDisplayWidget.DisplayType; + 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"; 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; @@ -37,6 +44,34 @@ 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( + "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(); } diff --git a/src/main/java/com/cubefury/vendingmachine/VendingMachine.java b/src/main/java/com/cubefury/vendingmachine/VendingMachine.java index 7ef5787..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; @@ -62,13 +65,13 @@ 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); - // ModularUI - WidgetThemes.register(); - } @Mod.EventHandler @@ -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/enums/Textures.java b/src/main/java/com/cubefury/vendingmachine/api/enums/Textures.java index 13af61d..277dfd2 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_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/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/blocks/MTEVendingMachine.java b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java index 54df808..a4ff659 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingMachine.java @@ -5,9 +5,12 @@ 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; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,6 +29,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; @@ -35,17 +39,18 @@ 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; 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; 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; @@ -79,12 +84,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( + ofHatchAdderOptional( + MTEVendingMachine::addUplinkHatch, + ((BlockCasings11) GregTechAPI.sBlockCasings11).getTextureIndex(0), + 1, + GregTechAPI.sBlockCasings11, + 0), + ofBlock(GregTechAPI.sBlockCasings11, 0))) .build(); private final ArrayList uplinkHatches = new ArrayList<>(); @@ -146,7 +153,7 @@ public boolean usingAnimations() { public void sendTradeRequest(TradeItemDisplay trade) { IGregTechTileEntity baseTile = getBaseMetaTileEntity(); - if (baseTile == null) { + if (baseTile == null || !baseTile.isActive()) { return; } NetTradeRequestSync.sendTradeRequest( @@ -162,6 +169,9 @@ public void addTradeRequest(TradeRequest trade) { } public void dispenseItems() { + if (!this.getActive()) { + return; + } if (!this.pendingTrades.isEmpty()) { TradeRequest tradeRequest = this.pendingTrades.poll(); if (!processTradeOnServer(tradeRequest)) { @@ -247,6 +257,7 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { if ( !this.inputCurrencySatisfied(trade.fromCurrency, tradeRequest.playerID) || !this.inputItemsSatisfied(trade.fromItems) + || !this.inputItemsSatisfied(trade.nonConsumedItems) ) { return false; } @@ -260,9 +271,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) { @@ -275,19 +286,17 @@ 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 + // 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) - && ItemStack.areItemStackTagsEqual(requiredStack, tmp) - ) { + if (ItemStack.areItemStacksEqual(requiredStack, tmp)) { if (requiredAmount >= inputSlots[i].stackSize) { requiredAmount -= inputSlots[i].stackSize; inputSlots[i] = null; @@ -297,13 +306,40 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { } } } + // Remove Items from last stacks if possible (oredict matches) + if (stack.hasOreDict()) { + int oreId = OreDictionary.getOreID(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 ( + Arrays.stream(OreDictionary.getOreIDs(tmp)) + .anyMatch(id -> id == oreId) + ) { + 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; } } - for (Map.Entry entry : newCoinInventory.entrySet()) { + for (Map.Entry entry : newCoinInventory.entrySet()) { if (entry.getValue() == 0) { coinInventory.remove(entry.getKey()); } else { @@ -327,9 +363,9 @@ private boolean processTradeOnServer(TradeRequest tradeRequest) { return true; } - public boolean fetchItemFromAE(ItemStack requiredStack, boolean simulate) { + public boolean fetchItemFromAE(ItemStack requiredStack, boolean simulate, String matchOreDict) { for (MTEVendingUplinkHatch hatch : this.uplinkHatches) { - if (hatch.removeItem(requiredStack, simulate)) { + if (hatch.removeItem(requiredStack, simulate, matchOreDict)) { return true; } } @@ -343,7 +379,7 @@ public boolean getDefaultHasMaintenanceChecks() { @Override public String[] getStructureDescription(ItemStack stackSize) { - return getTooltip().getStructureHint(); + return new String[] { Translator.translate("structure.vendingmachine.hint.1") }; } @Override @@ -359,6 +395,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(); } @@ -541,7 +578,7 @@ public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { } if (aBaseMetaTileEntity.isServerSide()) { dispenseItems(); - if (this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { + if (this.getActive() && this.ticksSinceTradeUpdate++ >= Config.gui_refresh_interval) { this.sendTradeUpdate(); } if (this.mUpdate++ % STRUCTURE_CHECK_TICKS == 0) { @@ -556,7 +593,6 @@ public void sendTradeUpdate() { if (this.currentUser == null) { return; } - NetCurrencySync.syncCurrencyToClient((EntityPlayerMP) this.currentUser); NetTradeDisplaySync.syncTradesToClient((EntityPlayerMP) this.currentUser, this); } @@ -566,6 +602,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); @@ -577,6 +614,9 @@ public void refreshInputSlotCache() { public boolean inputItemsSatisfied(List fromItems) { for (BigItemStack bis : fromItems) { BigItemStack base = bis.copy(); + boolean hasOreDict = bis.hasOreDict(); + int oreId = OreDictionary.getOreID(bis.getOreDict()); + bis.setTagCompound(null); base.stackSize = 1; // shouldn't need this, but just in case ItemStack aeStackSearch = base.getBaseStack(); @@ -584,11 +624,23 @@ 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) { + for (Map.Entry item : this.inputSlotCache.entrySet()) { + if ( + Arrays.stream( + OreDictionary.getOreIDs( + item.getKey() + .getBaseStack())) + .anyMatch(id -> id == oreId) + ) { + 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; } } @@ -599,7 +651,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; } @@ -744,4 +796,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 10e6d6b..55452f5 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/MTEVendingUplinkHatch.java @@ -1,14 +1,18 @@ 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_ACTIVE; +import static com.cubefury.vendingmachine.api.enums.Textures.VUPLINK_OVERLAY_INACTIVE; +import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumSet; +import java.util.List; 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; @@ -21,6 +25,7 @@ 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; @@ -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; @@ -120,12 +126,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_ACTIVE) }; } @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_INACTIVE) }; } @Override @@ -144,6 +150,14 @@ public void onFirstTick(IGregTechTileEntity baseMetaTileEntity) { getProxy().onReady(); } + @Override + public void onPostTick(IGregTechTileEntity baseMetaTileEntity, long tick) { + if (baseMetaTileEntity.isServerSide() && tick % 20 == 0) { + baseMetaTileEntity.setActive(isActive()); + } + super.onPostTick(baseMetaTileEntity, tick); + } + private void updateValidGridProxySides() { if (additionalConnection) { getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); @@ -172,15 +186,79 @@ private IStorageGrid accessStorage() { return null; } - public boolean removeItem(ItemStack remove, boolean simulate) { + public void refreshStorageContents() { + IStorageGrid storage = accessStorage(); + if (storage == null) return; + + cachedItems = storage.getItemInventory() + .getStorageList(); + } + + public boolean removeItem(ItemStack remove, boolean simulate, String matchOreDict) { if (remove == null || remove.stackSize <= 0) return true; IStorageGrid storage = accessStorage(); if (storage == null) return false; - IAEItemStack stack = storage.getItemInventory() - .extractItems( - AEItemStack.create(remove), - simulate ? Actionable.SIMULATE : Actionable.MODULATE, - new MachineSource(this)); - return stack != null && stack.getStackSize() >= remove.stackSize; + + MachineSource source = new MachineSource(this); + if (!remove.isItemStackDamageable() && matchOreDict != null) { + IAEItemStack stack = storage.getItemInventory() + .extractItems(AEItemStack.create(remove), simulate ? Actionable.SIMULATE : Actionable.MODULATE, source); + return stack != null && stack.getStackSize() >= remove.stackSize; + } + + if (cachedItems == null) { + return false; + } + + int oreId = OreDictionary.getOreID(matchOreDict); + List outputList = new ArrayList<>(); + for (IAEItemStack stack : cachedItems) { + // no oredict data: check if item + item damage matches required item + // oredict data: check if item contains desired oredict string + if ( + (matchOreDict == null && stack.getItem() == remove.getItem() + && stack.getItemDamage() == remove.getItemDamage()) + || (matchOreDict != null && Arrays.stream(OreDictionary.getOreIDs(stack.getItemStack())) + .anyMatch(id -> id == oreId)) + ) { + outputList.add(stack); + } + } + + long numMatch = outputList.stream() + .mapToLong(stack -> stack.getStackSize()) + .sum(); + 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/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/InterceptingSlot.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java index 582335e..a340e1c 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/InterceptingSlot.java @@ -1,30 +1,34 @@ 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.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); 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 5fcfd38..02798a3 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/MTEVendingMachineGui.java @@ -1,6 +1,10 @@ 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; import java.util.List; import java.util.Map; @@ -13,14 +17,21 @@ 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; 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.IntSyncValue; 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,23 +41,24 @@ 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; 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; +import com.cubefury.vendingmachine.trade.CurrencyType; import com.cubefury.vendingmachine.trade.TradeCategory; import com.cubefury.vendingmachine.trade.TradeDatabase; import com.cubefury.vendingmachine.trade.TradeManager; 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 { @@ -56,8 +68,9 @@ 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 ejectSingleCoin = 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,20 +80,50 @@ 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; - 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 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; + 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; + 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; - for (CurrencyItem.CurrencyType type : CurrencyItem.CurrencyType.values()) { + for (CurrencyType type : CurrencyType.values()) { ejectSingleCoin.put(type, false); } @@ -88,10 +131,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, this.base, 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, this.base, TradeItemDisplayWidget.DisplayType.LIST)); } } @@ -117,18 +165,23 @@ 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 - mainColumn.child(createTitleTextStyle(base.getLocalName())) + if (VendingMachine.proxy.isClient()) { // client side sort and filtering + panel.child(createQolButtonColumn()); + 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)); + mainColumn.child(createCoinInventoryRow((TradeMainPanel) panel, syncManager)); } mainColumn.child(createInventoryRow()); panel.child(mainColumn); panel.child( new Column().size(20) .right(5)); - panel.child(createIOColumn(syncManager)); + panel.child(createIOColumn()); return panel; } @@ -139,6 +192,47 @@ 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)); + 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; + } + public IWidget createCategoryTabs(PagedWidget.Controller tabController) { Flow tabColumn = new Column().width(40) .height(100) @@ -188,12 +282,12 @@ 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 - private void doEjectCoin(CurrencyItem.CurrencyType type) { - if (this.guiData.isClient()) { + private void doEjectCoin(CurrencyType type) { + if (this.guiData.isClient() || !this.base.getActive()) { return; } UUID currentUser = NameCache.INSTANCE.getUUIDFromPlayer(base.getCurrentUser()); @@ -212,7 +306,6 @@ private void doEjectCoin(CurrencyItem.CurrencyType type) { base.spawnItem(ejectable); } TradeManager.INSTANCE.resetCurrency(currentUser, type); - NetCurrencySync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), type); this.ejectSingleCoin.put(type, false); } @@ -221,21 +314,25 @@ 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; 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); } } TradeManager.INSTANCE.resetCurrency(currentUser, null); - NetCurrencySync.resetPlayerCurrency((EntityPlayerMP) base.getCurrentUser(), null); ejectCoins = false; } @@ -243,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) { @@ -253,8 +355,8 @@ private void doEjectItems() { ejectItems = false; } - private IWidget createIOColumn(PanelSyncManager syncManager) { - return new ParentWidget<>().excludeAreaInNEI() + private IWidget createIOColumn() { + return new ParentWidget<>().excludeAreaInRecipeViewer() .width(50) .height(178) .right(-48) @@ -268,7 +370,7 @@ private IWidget createIOColumn(PanelSyncManager syncManager) { .width(30) .height(20)) .child( - new Row().child(createInputRow().center()) + new Row().child(createInputSlots().center()) .top(20) .height(18 * 3)) .child( @@ -299,11 +401,11 @@ private IWidget createIOColumn(PanelSyncManager syncManager) { .right(1)); } - private SlotGroupWidget createInputRow() { + 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") @@ -336,74 +438,138 @@ 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); + return new ItemSlot().slot( + new ModularSlot(base.outputItems, index).accessibility(false, true) + .slotGroup("outputSlotGroup")); }) .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(); + + if (!cur.fromCurrency.isEmpty() || !cur.fromItems.isEmpty()) { + builder.addLine( + 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)); + } + builder.emptyLine(); + } + if (!cur.ncItems.isEmpty()) { + builder.addLine( + 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(); + } + + 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<>() + .name("paged") .width(162) - .debugName("paged") .controller(tabController) .background(GuiTextures.TEXT_FIELD_BACKGROUND) .height(146); for (TradeCategory category : this.tradeCategories) { - ListWidget tradeList = new ListWidget<>().debugName("items") - .width(156) + ListWidget tradeList = new ListWidget<>() + .name("items") + .width(161) .top(1) .height(144) .collapseDisabledChild(true); 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).width(TRADE_ROW_WIDTH).marginLeft(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)); + 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).width(TRADE_ROW_WIDTH).marginLeft(2); } } if (row.hasChildren()) { tradeList.child(row); } + + // List Display + 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); + 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).width(TRADE_ROW_WIDTH).marginLeft(2); + } + tradeList.child(new Row().height(2)); // bottom padding for last row paged.addPage(tradeList); } @@ -424,7 +590,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) @@ -432,36 +598,9 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { .left(3); Flow coinColumn = new Column().width(COIN_COLUMN_WIDTH); int coinCount = 0; - Map currentAmounts = TradeManager.INSTANCE.playerCurrency - .getOrDefault(NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()), new HashMap<>()); - for (CurrencyItem.CurrencyType type : CurrencyItem.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( - () -> getReadableStringFromCoinAmount( - currentAmounts.get(type) == null ? 0 : currentAmounts.get(type))) - .scale(0.8f) - .asWidget() - .top(3) - .left(14) - .width(21)) - .height(14)); + + for (CurrencyType type : CurrencyType.values()) { + 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); @@ -473,6 +612,34 @@ private IWidget createCoinInventoryRow(TradeMainPanel panel) { return parent; } + private IWidget createCoinDisplay(TradeMainPanel panel, CurrencyType type, PanelSyncManager syncManager) { + IntSyncValue coinSyncValue = syncManager.findSyncHandler("coinAmount_" + type.id, 0, IntSyncValue.class); + 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) @@ -488,8 +655,9 @@ 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; @@ -497,16 +665,23 @@ protected void registerSyncValues(PanelSyncManager syncManager) { doEjectItems(); } }); + syncManager.syncValue("ejectItems", ejectItemsSyncer); + BooleanSyncValue ejectCoinsSyncer = new BooleanSyncValue(() -> this.ejectCoins, val -> { this.ejectCoins = val; if (this.ejectCoins) { doEjectCoins(); } }); - syncManager.syncValue("ejectItems", ejectItemsSyncer); syncManager.syncValue("ejectCoins", ejectCoinsSyncer); - for (CurrencyItem.CurrencyType type : CurrencyItem.CurrencyType.values()) { + UUID playerId = NameCache.INSTANCE.getUUIDFromPlayer(getBase().getCurrentUser()); + for (CurrencyType type : CurrencyType.values()) { + IntSyncValue coinAmountSyncer = new IntSyncValue( + () -> TradeManager.INSTANCE.playerCurrency.getOrDefault(playerId, Collections.emptyMap()) + .getOrDefault(type, 0)); + syncManager.syncValue("coinAmount_" + type.id, coinAmountSyncer); + BooleanSyncValue ejectCoinSyncer = new BooleanSyncValue(() -> this.ejectSingleCoin.get(type), val -> { this.ejectSingleCoin.put(type, val); if (val) { @@ -515,6 +690,7 @@ protected void registerSyncValues(PanelSyncManager syncManager) { }); syncManager.syncValue("ejectCoin_" + type.id, ejectCoinSyncer); } + } public void attemptPurchase(TradeItemDisplay display) { @@ -533,9 +709,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(); @@ -556,10 +733,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() @@ -568,6 +751,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/SearchBar.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java index 72de631..b611874 100644 --- a/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java +++ b/src/main/java/com/cubefury/vendingmachine/blocks/gui/SearchBar.java @@ -5,9 +5,9 @@ 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.gui.WidgetThemes; import com.cubefury.vendingmachine.util.Translator; public class SearchBar extends BaseTextFieldWidget { @@ -19,8 +19,7 @@ public SearchBar(MTEVendingMachineGui gui) { super(); this.gui = gui; - - background(GuiTextures.TEXT_FIELD_BACKGROUND); + widgetTheme(WidgetThemes.BACKGROUND_SEARCH_BAR); setText(""); this.previousText = ""; hintText(Translator.translate("vendingmachine.gui.search")); @@ -69,9 +68,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/TradeItemDisplay.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplay.java index 1845e84..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,27 +14,27 @@ public class TradeItemDisplay { public List fromCurrency; public List fromItems; + public List ncItems; public List toItems; public ItemStack display; public UUID tgID; public int tradeGroupOrder; - public String label; public long cooldown; public String cooldownText; public boolean hasCooldown; public boolean enabled; 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) { + 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; this.tradeGroupOrder = tradeGroupOrder; - this.label = label; this.cooldown = cooldown; this.cooldownText = cooldownText; this.hasCooldown = hasCooldown; @@ -43,10 +43,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/blocks/gui/TradeItemDisplayWidget.java b/src/main/java/com/cubefury/vendingmachine/blocks/gui/TradeItemDisplayWidget.java index 65641ef..5125b14 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,27 +12,69 @@ 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.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.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; 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; 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, MTEVendingMachine base, DisplayType displayType) { + this.vm = base; + 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)); + } 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); @@ -40,6 +85,10 @@ public void setDisplay(TradeItemDisplay display) { this.item(display == null ? null : display.display); } + private boolean checkVmActive() { + return this.vm != null && this.vm.getActive(); + } + public TradeItemDisplay getDisplay() { return this.display; } @@ -54,27 +103,62 @@ 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)) { - 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, textColor, false); + GuiDraw.drawItem(item, 26, 4, 16, 16, context.getCurrentDrawingZ()); + if (this.display.tradeableNow) { + GuiDraw.drawOutline(1, 1, 45, 23, 0x883CFF00, 2); + } + if (!this.checkVmActive() || 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, 6, 4, 0.9f, textColor, 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, + textColor, + 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.checkVmActive() || 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)); } } @@ -96,6 +180,7 @@ public ItemDisplayWidget item(IValue itemSupplier) { @Override public void onMouseEndHover() { pressed = false; + super.onMouseEndHover(); } @Override 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..37cbccc 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; @@ -64,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); @@ -125,9 +126,14 @@ 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) { - 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); @@ -152,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 8ee5829..2a9c414 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; @@ -45,20 +48,63 @@ public final class GuiTextures { .name("text_field_background") .build(); - public static final UITexture TRADE_BUTTON_UNPRESSED = UITexture.builder() - .location(VendingMachine.MODID, "gui/background/trade_button_unpressed_color_corrected") + // 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") + .canApplyTheme() .imageSize(195, 136) .adaptable(4) .name("trade_button_unpressed") .build(); - public static final UITexture TRADE_BUTTON_PRESSED = UITexture.builder() - .location(VendingMachine.MODID, "gui/background/trade_button_pressed_color_corrected") + public static final UITexture TILE_TRADE_BUTTON_PRESSED = UITexture.builder() + .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") + .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") + .canApplyTheme() + .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 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) @@ -77,6 +123,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..3aa882f 100644 --- a/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java +++ b/src/main/java/com/cubefury/vendingmachine/gui/WidgetThemes.java @@ -1,23 +1,42 @@ package com.cubefury.vendingmachine.gui; import com.cleanroommc.modularui.api.IThemeApi; -import com.cleanroommc.modularui.drawable.UITexture; +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 final String BACKGROUND_SIDEPANEL = "background_side_panel"; + public static void init() {} - public static void register() { - IThemeApi themeApi = IThemeApi.get(); - registerThemedTexture(themeApi, BACKGROUND_SIDEPANEL, GuiTextures.SIDE_PANEL_BACKGROUND); - } + private static final IThemeApi themeApi = IThemeApi.get(); - private static void registerThemedTexture(IThemeApi themeApi, String textureThemeId, UITexture background) { - themeApi.registerWidgetTheme( - textureThemeId, - new WidgetTheme(background, null, Color.WHITE.main, 0xFF404040, false), - WidgetTheme::new); - } + 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(); + + 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(); } 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/handlers/SaveLoadHandler.java b/src/main/java/com/cubefury/vendingmachine/handlers/SaveLoadHandler.java index 8bb920e..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; @@ -30,6 +31,7 @@ public class SaveLoadHandler { private File fileDatabase = null; private File fileNames = null; private File dirTradeState = null; + private File dirBackupTradeState = null; private SaveLoadHandler() {} @@ -42,10 +44,13 @@ 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(); + unloadAll(); + loadDatabase(); loadTradeState(); loadNames(); @@ -79,7 +84,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) { @@ -90,17 +94,21 @@ public void loadTradeState() { .endsWith(".json")) .collect(Collectors.toList())); } else { - JsonHelper.populateTradeStateFromFiles(new ArrayList<>()); + JsonHelper.populateTradeStateFromFiles(Collections.emptyList()); } } } 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))); } 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/NEIConfig.java b/src/main/java/com/cubefury/vendingmachine/integration/nei/NEIConfig.java index 9a16209..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,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(140) + .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..abb1921 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; @@ -58,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; @@ -178,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 @@ -197,8 +198,12 @@ 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; + // 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.getWidgetSize().width) / 2; - int guiTop = 19 + (gui.height - gui.getWidgetSize().height) / 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(); @@ -264,10 +271,23 @@ 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, - 27, + 63, textColorConditionDefault, false); int y = CONDITIONS_START_Y; @@ -286,7 +306,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); @@ -310,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<>(); @@ -325,20 +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 (CurrencyItem ci : trade.fromCurrency) { if (index >= GRID_COUNT) { - break; + y += SLOT_SIZE; + index = 0; } int x = xOffset + index * SLOT_SIZE; inputs.add(new PositionedStack(ci.getItemRepresentation(), x, y)); index++; } + + y += SLOT_SIZE; + index = 0; + for (BigItemStack stack : trade.nonConsumedItems) { + if (index >= GRID_COUNT) { + y += SLOT_SIZE; + index = 0; + } + int x = xOffset + index * SLOT_SIZE; + ncInputs.add(new PositionedStack(extractStacks(stack), x, y)); + index++; + } + } private void loadOutputs(Trade trade) { @@ -361,7 +400,10 @@ 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 @@ -372,6 +414,6 @@ public List getOtherStacks() { @Override public void loadTransferRects() { - transferRects.add(new RecipeTransferRect(new Rectangle(75, 0, 16, 24), getOverlayIdentifier())); + transferRects.add(new RecipeTransferRect(new Rectangle(75, 5, 16, 55), getOverlayIdentifier())); } } 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/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/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/network/handlers/NetCurrencySync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetCurrencySync.java deleted file mode 100644 index 84d8f61..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.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 tradegroup 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)); - - 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 CurrencyItem.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") ? CurrencyItem.CurrencyType.getTypeFromId(message.getString("type")) : null); - default -> VendingMachine.LOG.warn("Unknown trade state sync data received: {}", dataType); - } - } -} diff --git a/src/main/java/com/cubefury/vendingmachine/network/handlers/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/network/handlers/NetTradeDisplaySync.java b/src/main/java/com/cubefury/vendingmachine/network/handlers/NetTradeDisplaySync.java index a399f08..4ac7275 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,16 +79,14 @@ public TradeItemDisplay formatItemDisplay() { TradeGroup tg = TradeDatabase.INSTANCE.getTradeGroupFromId(this.tgID); Trade t = tg.getTrades() .get(this.tradeGroupOrder); - ItemStack displayItem = t.toItems.get(0) - .convertToItemStack(); return new TradeItemDisplay( t.fromCurrency, t.fromItems, + t.nonConsumedItems, t.toItems, - t.displayItem == null ? t.displayItem.convertToItemStack() : displayItem, + t.getDisplayItem(), this.tgID, this.tradeGroupOrder, - tg.getLabel(), this.cooldown, convertCooldownText(this.cooldown), this.cooldown > 0, @@ -115,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(); @@ -137,6 +135,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) @@ -150,7 +149,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(); 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) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java b/src/main/java/com/cubefury/vendingmachine/trade/CurrencyItem.java index a0535af..495ae3f 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 }; @@ -44,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)); @@ -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/Trade.java b/src/main/java/com/cubefury/vendingmachine/trade/Trade.java index a0f9a7c..8a3c70b 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; @@ -22,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); @@ -44,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) { @@ -56,6 +66,8 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { } public void readFromNBT(NBTTagCompound nbt) { + displayItem = BigItemStack.loadItemStackFromNBT(nbt.getCompoundTag("displayItem")); + fromCurrency.clear(); fromItems.clear(); toItems.clear(); @@ -70,15 +82,29 @@ 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))); } } + 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); } + } diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java index a6e669a..4a4ca50 100644 --- a/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java +++ b/src/main/java/com/cubefury/vendingmachine/trade/TradeDatabase.java @@ -9,10 +9,13 @@ import java.util.Set; import java.util.UUID; +import javax.annotation.Nonnull; + import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.common.util.Constants; +import com.cubefury.vendingmachine.Config; import com.cubefury.vendingmachine.VendingMachine; import com.cubefury.vendingmachine.integration.betterquesting.BqAdapter; import com.cubefury.vendingmachine.integration.nei.NeiRecipeCache; @@ -38,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) { @@ -71,7 +75,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) { @@ -94,7 +98,7 @@ public void readFromNBT(NBTTagCompound nbt, boolean merge) { tradeGroups.put(tg.getId(), tg); } - if (newMetadataCount > 0) { + if (isFileLoad && (Config.forceRewriteDatabase || newMetadataCount > 0)) { VendingMachine.LOG.info("Appended metadata to {} new trades", newMetadataCount); DirtyDbMarker.markDirty(); } @@ -109,9 +113,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; } @@ -126,12 +131,14 @@ 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); } - 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() @@ -145,7 +152,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/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) { diff --git a/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java b/src/main/java/com/cubefury/vendingmachine/trade/TradeManager.java index d527cd6..058f734 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; @@ -24,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<>(); @@ -103,14 +105,12 @@ 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(); + this.clearCurrency(player); } 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<>()); @@ -130,28 +130,29 @@ 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; } - for (Map.Entry entry : this.playerCurrency.get(player) + 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; } - 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) @@ -176,4 +177,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 0dc336f..f3390d0 100644 --- a/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java +++ b/src/main/java/com/cubefury/vendingmachine/util/JsonHelper.java @@ -50,17 +50,14 @@ 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); - db.readFromNBT(readNbt.apply(file), false); + db.readFromNBT(readNbt.apply(file), false, true); } 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); diff --git a/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java b/src/main/java/com/cubefury/vendingmachine/util/NBTConverter.java index 5daf73f..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; @@ -176,20 +175,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 { @@ -203,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(); } @@ -233,31 +226,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(); diff --git a/src/main/resources/assets/vendingmachine/lang/en_US.lang b/src/main/resources/assets/vendingmachine/lang/en_US.lang index 70de284..28ae3b8 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 @@ -14,7 +16,16 @@ 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.nc_inputs_overlay_color=FDD835 +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.display_text_color=000000 vendingmachine.gui.cooldown_display.second=s vendingmachine.gui.cooldown_display.minute=m vendingmachine.gui.cooldown_display.hour=h @@ -23,6 +34,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 2893c68..40f3eea 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=提示 1:锡质物品管道外壳,ME自动售货接入接口 + vendingmachine.gui.requirementHeader=需求条件: vendingmachine.gui.requirement.unknown=未知需求 vendingmachine.gui.requirement.betterquesting=任务 @@ -10,15 +12,22 @@ 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-点击购买 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=自动售货机 +gt.blockmachines.multimachine.vendingmachine.name.gui=自动售货机 +hatch.vendinguplink.me.name=ME自动售货接入接口 vendingmachine.category.unknown=未知分类 vendingmachine.category.all=全部物品 @@ -29,3 +38,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=巫师代币 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 0000000..358ce0b Binary files /dev/null and b/src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_active.png differ 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 new file mode 100644 index 0000000..2393590 Binary files /dev/null and b/src/main/resources/assets/vendingmachine/textures/blocks/vending_uplink_machine_overlay_inactive.png differ 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/list_trade_button_pressed.png similarity index 83% rename from src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_unpressed_color_corrected.png rename to src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed.png index 13c9e01..aefd2f7 100644 Binary files a/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_unpressed_color_corrected.png and b/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_pressed.png differ 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 0000000..48b5d22 Binary files /dev/null and b/src/main/resources/assets/vendingmachine/textures/gui/background/list_trade_button_unpressed.png differ 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 1c15f01..0000000 Binary files a/src/main/resources/assets/vendingmachine/textures/gui/background/trade_button_pressed_color_corrected.png and /dev/null differ diff --git a/src/main/resources/assets/vendingmachine/textures/gui/nei.png b/src/main/resources/assets/vendingmachine/textures/gui/nei.png index be099bd..bf64099 100644 Binary files a/src/main/resources/assets/vendingmachine/textures/gui/nei.png and b/src/main/resources/assets/vendingmachine/textures/gui/nei.png differ 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 0000000..039e5ef Binary files /dev/null and b/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_list.png differ 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 0000000..426e54f Binary files /dev/null and b/src/main/resources/assets/vendingmachine/textures/gui/overlay/mode_tile.png differ 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 0000000..19f0991 Binary files /dev/null and b/src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_alphabet.png differ 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 0000000..7df0dc2 Binary files /dev/null and b/src/main/resources/assets/vendingmachine/textures/gui/overlay/sort_smart.png differ 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 0c532c6..9e5b665 100644 Binary files a/src/main/resources/assets/vendingmachine/textures/gui/tabs_left.png and b/src/main/resources/assets/vendingmachine/textures/gui/tabs_left.png differ