diff --git a/mods/ShopMod.properties b/mods/ShopMod.properties index e65e2e8..6d2164a 100644 --- a/mods/ShopMod.properties +++ b/mods/ShopMod.properties @@ -17,3 +17,8 @@ itemJsonPath=mods/shop_items.json # java.util.logging level for this mod (e.g., INFO, FINE) logLevel=INFO + +# Dump trader inventories to a shop_items.json-compatible file on startup (set back to false after dumping) +dumpTraders=true +dumpTradersCategoryId=1 +dumpTradersOutputPath=mods/shop_items.json diff --git a/src/main/java/mod/treestar/shopmod/ShopMod.java b/src/main/java/mod/treestar/shopmod/ShopMod.java index fe6cc45..5cb156d 100644 --- a/src/main/java/mod/treestar/shopmod/ShopMod.java +++ b/src/main/java/mod/treestar/shopmod/ShopMod.java @@ -3,6 +3,7 @@ package mod.treestar.shopmod; import mod.treestar.shopmod.categoryprovider.JsonShopCategoryProvider; import mod.treestar.shopmod.itemprovider.JsonShopItemProvider; import mod.treestar.shopmod.ShopOpenAction; +import mod.treestar.shopmod.util.TraderItemExporter; import org.gotti.wurmunlimited.modloader.interfaces.Configurable; import org.gotti.wurmunlimited.modloader.interfaces.Initable; import org.gotti.wurmunlimited.modloader.interfaces.ServerStartedListener; @@ -23,6 +24,9 @@ public class ShopMod implements WurmServerMod, Initable, Configurable, ServerSta private String itemJsonPath = "mods/shop/items.json"; private Level logLevel = Level.INFO; private ShopService shopService; + private boolean dumpTraders = false; + private int dumpTradersCategoryId = 1; + private String dumpTradersOutputPath = "mods/shop/items.json"; @Override public void configure(Properties properties) { @@ -32,6 +36,9 @@ public class ShopMod implements WurmServerMod, Initable, Configurable, ServerSta categoryJsonPath = properties.getProperty("categoryJsonPath", categoryJsonPath); itemJsonPath = properties.getProperty("itemJsonPath", itemJsonPath); logLevel = getLogLevel(properties.getProperty("logLevel", logLevel.getName())); + dumpTraders = getBoolean(properties, "dumpTraders", dumpTraders); + dumpTradersCategoryId = getInt(properties, "dumpTradersCategoryId", dumpTradersCategoryId); + dumpTradersOutputPath = properties.getProperty("dumpTradersOutputPath", itemJsonPath); logger.setLevel(logLevel); } @@ -49,6 +56,14 @@ public class ShopMod implements WurmServerMod, Initable, Configurable, ServerSta new ShopOpenAction(shopService, shopName, enableTokenAccess, enableMailboxAccess); logger.log(Level.INFO, String.format("Initialized shop '%s' (token access: %s, mailbox access: %s)", shopName, enableTokenAccess, enableMailboxAccess)); + + if (dumpTraders) { + try { + TraderItemExporter.dumpTraderItems(dumpTradersOutputPath, dumpTradersCategoryId); + } catch (Exception e) { + logger.log(Level.WARNING, "Failed to dump trader items", e); + } + } } /** @@ -70,4 +85,13 @@ public class ShopMod implements WurmServerMod, Initable, Configurable, ServerSta return logLevel; } } + + private int getInt(Properties properties, String key, int defaultValue) { + try { + return Integer.parseInt(properties.getProperty(key, Integer.toString(defaultValue))); + } catch (NumberFormatException e) { + logger.log(Level.WARNING, String.format("Invalid int for key '%s', defaulting to %d", key, defaultValue)); + return defaultValue; + } + } } diff --git a/src/main/java/mod/treestar/shopmod/util/TraderItemExporter.java b/src/main/java/mod/treestar/shopmod/util/TraderItemExporter.java new file mode 100644 index 0000000..be39944 --- /dev/null +++ b/src/main/java/mod/treestar/shopmod/util/TraderItemExporter.java @@ -0,0 +1,89 @@ +package mod.treestar.shopmod.util; + +import com.wurmonline.server.Items; +import com.wurmonline.server.creatures.Creature; +import com.wurmonline.server.creatures.Creatures; +import com.wurmonline.server.items.Item; +import com.wurmonline.server.support.JSONArray; +import com.wurmonline.server.support.JSONObject; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Utility to dump the current contents of all traders into a shop_items.json compatible array. + */ +public class TraderItemExporter { + private static final Logger logger = Logger.getLogger(TraderItemExporter.class.getName()); + + public static void dumpTraderItems(String outputPath, int categoryId) { + JSONArray out = new JSONArray(); + AtomicInteger id = new AtomicInteger(1); + + Set seenTemplates = new HashSet<>(); + for (Creature c : Creatures.getInstance().getCreatures()) { + if (c == null || !c.isTrader()) { + continue; + } + logger.log(Level.INFO, "Trader found"); + try { + for (Item it : c.getAllItems()) { + if (it.isCoin()) { + continue; // skip currency + } + if(it.isBodyPart()) { + continue; // Skip body parts + } + if(seenTemplates.contains(it.getTemplateId())) { + continue; + } + seenTemplates.add(it.getTemplateId()); + JSONObject obj = new JSONObject(); + obj.put("id", id.getAndIncrement()); + obj.put("categoryId", categoryId); + obj.put("name", it.getName()); + obj.put("description", it.getTemplate().getDescriptionLong()); + obj.put("image", ""); + JSONObject currency = new JSONObject(); + currency.put("type", "WurmBankCurrency"); + currency.put("ironAmount", it.getValue()); + obj.put("currency", currency); + JSONObject handler = new JSONObject(); + handler.put("type", "ShopWurmItemPurchaseEffect"); + handler.put("itemTemplateId", it.getTemplateId()); + handler.put("ql", it.getQualityLevel()); + handler.put("rarity", (int) it.getRarity()); + obj.put("handler", handler); + out.put(obj); + } + } catch (Exception e) { + logger.log(Level.WARNING, "Failed exporting items for trader " + c.getName(), e); + } + } + + writeToFile(out, outputPath); + } + + private static void writeToFile(JSONArray out, String outputPath) { + Path path = Paths.get(outputPath); + try { + if (path.getParent() != null) { + Files.createDirectories(path.getParent()); + } + try (FileWriter fw = new FileWriter(path.toFile())) { + fw.write(out.toString(2)); + } + logger.info("Dumped " + out.length() + " trader items to " + path.toAbsolutePath()); + } catch (IOException e) { + logger.log(Level.WARNING, "Failed writing trader dump to " + outputPath, e); + } + } +}