diff --git a/core/src/main/java/github/nighter/smartspawner/extras/HopperHandler.java b/core/src/main/java/github/nighter/smartspawner/extras/HopperHandler.java index 105f8537..ad4207a2 100644 --- a/core/src/main/java/github/nighter/smartspawner/extras/HopperHandler.java +++ b/core/src/main/java/github/nighter/smartspawner/extras/HopperHandler.java @@ -241,7 +241,7 @@ private void transferItems(Location hopperLoc, Location spawnerLoc) { } if (!itemsToRemove.isEmpty()) { - virtualInv.removeItems(itemsToRemove); + spawner.removeItemsAndUpdateSellValue(itemsToRemove); } if (inventoryChanged) { diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/gui/main/SpawnerMenuUI.java b/core/src/main/java/github/nighter/smartspawner/spawner/gui/main/SpawnerMenuUI.java index 7aa185a0..a566c36c 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/gui/main/SpawnerMenuUI.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/gui/main/SpawnerMenuUI.java @@ -360,6 +360,10 @@ public ItemStack createSpawnerInfoItem(Player player, SpawnerData spawner) { placeholders.put("raw_max_exp", String.valueOf(maxExp)); placeholders.put("formatted_exp", formattedPercentExp); + // Total sell price information + double totalSellPrice = spawner.getAccumulatedSellValue(); + placeholders.put("total_sell_price", languageManager.formatNumber(totalSellPrice)); + // Set display name with the specified placeholders spawnerMeta.setDisplayName(languageManager.getGuiItemName("spawner_info_item.name", placeholders)); diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageAction.java b/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageAction.java index 847b0dc5..ff761609 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageAction.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageAction.java @@ -282,7 +282,7 @@ private void handleItemDrop(Player player, SpawnerData spawner, Inventory invent VirtualInventory virtualInv = spawner.getVirtualInventory(); List itemsToRemove = new ArrayList<>(); itemsToRemove.add(droppedItem); - virtualInv.removeItems(itemsToRemove); + spawner.removeItemsAndUpdateSellValue(itemsToRemove); int remaining = item.getAmount() - amountToDrop; if (remaining <= 0) { @@ -363,7 +363,7 @@ private void handleDropPageItems(Player player, SpawnerData spawner, Inventory i } VirtualInventory virtualInv = spawner.getVirtualInventory(); - virtualInv.removeItems(pageItems); + spawner.removeItemsAndUpdateSellValue(pageItems); dropItemsInDirection(player, pageItems); @@ -445,7 +445,7 @@ private void takeSingleItem(Player player, Inventory sourceInv, int slot, ItemSt ); if (result.getAmountMoved() > 0) { updateInventorySlot(sourceInv, slot, item, result.getAmountMoved()); - virtualInv.removeItems(result.getMovedItems()); + spawner.removeItemsAndUpdateSellValue(result.getMovedItems()); player.updateInventory(); spawner.updateHologramData(); @@ -767,8 +767,8 @@ else if (targetItem.isSimilar(itemToMove)) { } if (!itemsToRemove.isEmpty()) { - virtualInv.removeItems(itemsToRemove); StoragePageHolder holder = (StoragePageHolder) sourceInventory.getHolder(false); + holder.getSpawnerData().removeItemsAndUpdateSellValue(itemsToRemove); holder.getSpawnerData().updateHologramData(); holder.updateOldUsedSlots(); } diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageUI.java b/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageUI.java index 5086646d..47f4ab1b 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageUI.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/gui/storage/SpawnerStorageUI.java @@ -121,15 +121,8 @@ private void initializeStaticButtons() { )); } - // Create sell button - GuiButton sellButton = layout.getButton("sell_all"); - if (sellButton != null) { - staticButtons.put("sell", createButton( - sellButton.getMaterial(), - languageManager.getGuiItemName("sell_button.name"), - languageManager.getGuiItemLoreAsList("sell_button.lore") - )); - } + // Note: Sell button is created dynamically in updateDynamicButtons() + // to show the current total sell price } public Inventory createInventory(SpawnerData spawner, String title, int page, int totalPages) { @@ -293,7 +286,7 @@ private void addNavigationButtons(Map updates, SpawnerData s // Add sell button if shop integration is available and button is enabled if (layout.hasButton("sell_all")) { GuiButton sellButton = layout.getButton("sell_all"); - ItemStack sellIndicator = createSellButton(sellButton.getMaterial()); + ItemStack sellIndicator = createSellButton(spawner, sellButton.getMaterial()); updates.put(sellButton.getSlot(), sellIndicator); } } @@ -335,8 +328,13 @@ private ItemStack createNavigationButton(String type, int targetPage, Material m return createButton(material, buttonName, Arrays.asList(buttonLore)); } - private ItemStack createSellButton(Material material) { - String name = languageManager.getGuiItemName("sell_button.name"); + private ItemStack createSellButton(SpawnerData spawner, Material material) { + // Create placeholders for total sell price + Map placeholders = new HashMap<>(); + double totalSellPrice = spawner.getAccumulatedSellValue(); + placeholders.put("total_sell_price", languageManager.formatNumber(totalSellPrice)); + + String name = languageManager.getGuiItemName("sell_button.name", placeholders); List lore = languageManager.getGuiItemLoreAsList("sell_button.lore"); return createButton(material, name, lore); } diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java b/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java index 3971fdf0..a03adf17 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java @@ -188,7 +188,7 @@ public void spawnLootToSpawner(SpawnerData spawner) { } if (!itemsToAdd.isEmpty()) { - spawner.getVirtualInventory().addItems(itemsToAdd); + spawner.addItemsAndUpdateSellValue(itemsToAdd); changed = true; } } diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java b/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java index ad28c509..11147ffd 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java @@ -87,6 +87,11 @@ public class SpawnerData { private SellResult lastSellResult; @Getter private boolean lastSellProcessed; + + // Accumulated sell value for optimization + @Getter + private volatile double accumulatedSellValue; + private volatile boolean sellValueDirty; private SpawnerHologram hologram; @Getter @Setter @@ -117,6 +122,8 @@ private void initializeDefaults() { this.stackSize = 1; this.lastSpawnTime = System.currentTimeMillis(); this.preferredSortItem = null; // Initialize sort preference as null + this.accumulatedSellValue = 0.0; + this.sellValueDirty = true; } public void loadConfigurationValues() { @@ -135,6 +142,8 @@ public void recalculateAfterConfigReload() { if (virtualInventory != null && virtualInventory.getMaxSlots() != maxSpawnerLootSlots) { recreateVirtualInventory(); } + // Mark sell value as dirty after config reload since prices may have changed + this.sellValueDirty = true; updateHologramData(); // Invalidate GUI cache after config reload @@ -300,6 +309,8 @@ public boolean updateCapacityStatus() { public void setEntityType(EntityType newType) { this.entityType = newType; this.lootConfig = lootRegistry.getLootConfig(newType); + // Mark sell value as dirty since entity type and prices changed + this.sellValueDirty = true; updateHologramData(); } @@ -333,6 +344,8 @@ public int getEntityExperienceValue() { public void setLootConfig() { this.lootConfig = lootRegistry.getLootConfig(entityType); + // Mark sell value as dirty since prices may have changed + this.sellValueDirty = true; } public void setLastSellResult(SellResult sellResult) { @@ -360,4 +373,223 @@ public void updateLastInteractedPlayer(String playerName) { this.lastInteractedPlayer = playerName; markInteracted(); } + + /** + * Marks the sell value as dirty, requiring recalculation + */ + public void markSellValueDirty() { + this.sellValueDirty = true; + } + + /** + * Updates the accumulated sell value for specific items being added + * @param itemsAdded Map of item signatures to quantities added + * @param priceCache Price cache from loot config + */ + public void incrementSellValue(Map itemsAdded, + Map priceCache) { + if (itemsAdded == null || itemsAdded.isEmpty()) { + return; + } + + double addedValue = 0.0; + for (Map.Entry entry : itemsAdded.entrySet()) { + ItemStack template = entry.getKey().getTemplate(); + long amount = entry.getValue(); + double itemPrice = findItemPrice(template, priceCache); + if (itemPrice > 0.0) { + addedValue += itemPrice * amount; + } + } + + this.accumulatedSellValue += addedValue; + this.sellValueDirty = false; + } + + /** + * Decrements the accumulated sell value when items are removed + * @param itemsRemoved List of items removed + * @param priceCache Price cache from loot config + */ + public void decrementSellValue(List itemsRemoved, Map priceCache) { + if (itemsRemoved == null || itemsRemoved.isEmpty()) { + return; + } + + // Consolidate removed items + Map consolidated = new java.util.HashMap<>(); + for (ItemStack item : itemsRemoved) { + if (item == null || item.getAmount() <= 0) continue; + VirtualInventory.ItemSignature sig = new VirtualInventory.ItemSignature(item); + consolidated.merge(sig, (long) item.getAmount(), Long::sum); + } + + double removedValue = 0.0; + for (Map.Entry entry : consolidated.entrySet()) { + ItemStack template = entry.getKey().getTemplate(); + long amount = entry.getValue(); + double itemPrice = findItemPrice(template, priceCache); + if (itemPrice > 0.0) { + removedValue += itemPrice * amount; + } + } + + this.accumulatedSellValue = Math.max(0.0, this.accumulatedSellValue - removedValue); + } + + /** + * Forces a full recalculation of the accumulated sell value + * Should be called when the cache is dirty or on spawner load + */ + public void recalculateSellValue() { + if (lootConfig == null) { + this.accumulatedSellValue = 0.0; + this.sellValueDirty = false; + return; + } + + // Get price cache + Map priceCache = createPriceCache(); + + // Calculate from current inventory + Map items = virtualInventory.getConsolidatedItems(); + double totalValue = 0.0; + + for (Map.Entry entry : items.entrySet()) { + ItemStack template = entry.getKey().getTemplate(); + long amount = entry.getValue(); + double itemPrice = findItemPrice(template, priceCache); + if (itemPrice > 0.0) { + totalValue += itemPrice * amount; + } + } + + this.accumulatedSellValue = totalValue; + this.sellValueDirty = false; + } + + /** + * Gets the price cache from loot config + */ + public Map createPriceCache() { + if (lootConfig == null) { + return new java.util.HashMap<>(); + } + + Map cache = new java.util.HashMap<>(); + java.util.List allLootItems = lootConfig.getAllItems(); + + for (LootItem lootItem : allLootItems) { + if (lootItem.getSellPrice() > 0.0) { + ItemStack template = lootItem.createItemStack(new java.util.Random()); + if (template != null) { + String key = createItemKey(template); + cache.put(key, lootItem.getSellPrice()); + } + } + } + + return cache; + } + + /** + * Finds item price using the cache + */ + private double findItemPrice(ItemStack item, Map priceCache) { + if (item == null || priceCache == null) { + return 0.0; + } + String itemKey = createItemKey(item); + Double price = priceCache.get(itemKey); + return price != null ? price : 0.0; + } + + /** + * Creates a unique key for an item (same logic as SpawnerSellManager) + */ + private String createItemKey(ItemStack item) { + if (item == null) { + return "null"; + } + + StringBuilder key = new StringBuilder(); + key.append(item.getType().name()); + + // Add enchantments if present + if (item.hasItemMeta() && item.getItemMeta().hasEnchants()) { + key.append("_enchants:"); + item.getItemMeta().getEnchants().entrySet().stream() + .sorted(java.util.Map.Entry.comparingByKey(java.util.Comparator.comparing(enchantment -> enchantment.getKey().toString()))) + .forEach(entry -> key.append(entry.getKey().getKey()).append(":").append(entry.getValue()).append(",")); + } + + // Add custom model data if present + if (item.hasItemMeta() && item.getItemMeta().hasCustomModelData()) { + key.append("_cmd:").append(item.getItemMeta().getCustomModelData()); + } + + // Add display name if present + if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) { + key.append("_name:").append(item.getItemMeta().getDisplayName()); + } + + return key.toString(); + } + + /** + * Checks if sell value needs recalculation + */ + public boolean isSellValueDirty() { + return sellValueDirty; + } + + /** + * Adds items to virtual inventory and updates accumulated sell value + * This is the preferred method to add items to maintain accurate sell value cache + * @param items Items to add + */ + public void addItemsAndUpdateSellValue(List items) { + if (items == null || items.isEmpty()) { + return; + } + + // Consolidate items being added for efficient price lookup + Map itemsToAdd = new java.util.HashMap<>(); + for (ItemStack item : items) { + if (item == null || item.getAmount() <= 0) continue; + VirtualInventory.ItemSignature sig = new VirtualInventory.ItemSignature(item); + itemsToAdd.merge(sig, (long) item.getAmount(), Long::sum); + } + + // Add to inventory + virtualInventory.addItems(items); + + // Update sell value + if (!sellValueDirty) { + Map priceCache = createPriceCache(); + incrementSellValue(itemsToAdd, priceCache); + } + } + + /** + * Removes items from virtual inventory and updates accumulated sell value + * @param items Items to remove + * @return true if items were removed successfully + */ + public boolean removeItemsAndUpdateSellValue(List items) { + if (items == null || items.isEmpty()) { + return true; + } + + // Remove from inventory + boolean removed = virtualInventory.removeItems(items); + + // Update sell value if removal was successful + if (removed && !sellValueDirty) { + Map priceCache = createPriceCache(); + decrementSellValue(items, priceCache); + } + + return removed; + } } \ No newline at end of file diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/sell/SpawnerSellManager.java b/core/src/main/java/github/nighter/smartspawner/spawner/sell/SpawnerSellManager.java index ad9859fe..dcb0fa89 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/sell/SpawnerSellManager.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/sell/SpawnerSellManager.java @@ -28,7 +28,7 @@ public SpawnerSellManager(SmartSpawner plugin) { /** * Sells all items from the spawner's virtual inventory - * This method is async-optimized and handles large inventories efficiently + * This method is async-optimized and uses cached sell values for efficiency */ public void sellAllItems(Player player, SpawnerData spawner) { // Try to acquire lock for thread safety @@ -46,13 +46,19 @@ public void sellAllItems(Player player, SpawnerData spawner) { messageService.sendMessage(player, "no_items"); return; } + + // Recalculate sell value if dirty (should rarely happen) + if (spawner.isSellValueDirty()) { + spawner.recalculateSellValue(); + } - // Get all items for async processing + // Get all items for processing Map consolidatedItems = virtualInv.getConsolidatedItems(); // Process selling async to avoid blocking main thread Scheduler.runTaskAsync(() -> { - SellResult result = calculateSellValue(consolidatedItems, spawner); + // Use cached sell value for optimization + SellResult result = calculateSellValueOptimized(consolidatedItems, spawner); // Store the result in SpawnerData for later access spawner.setLastSellResult(result); @@ -112,8 +118,8 @@ private void processSellResult(Player player, SpawnerData spawner, SellResult se return; } - // Remove sold items from virtual inventory - boolean itemsRemoved = virtualInv.removeItems(sellResult.getItemsToRemove()); + // Remove sold items from virtual inventory and update sell value + boolean itemsRemoved = spawner.removeItemsAndUpdateSellValue(sellResult.getItemsToRemove()); if (!itemsRemoved) { // If items couldn't be removed (race condition), this indicates a critical issue // The money has already been deposited, so we need to log this for investigation @@ -154,6 +160,7 @@ private void processSellResult(Player player, SpawnerData spawner, SellResult se /** * Get the current sell value without actually selling (preview) + * Uses cached value for optimization */ public SellResult previewSellValue(SpawnerData spawner) { boolean lockAcquired = spawner.getLock().tryLock(); @@ -166,16 +173,54 @@ public SellResult previewSellValue(SpawnerData spawner) { if (virtualInv.getUsedSlots() == 0) { return SellResult.empty(); } + + // Recalculate if dirty + if (spawner.isSellValueDirty()) { + spawner.recalculateSellValue(); + } Map consolidatedItems = new HashMap<>(virtualInv.getConsolidatedItems()); - return calculateSellValue(consolidatedItems, spawner); + return calculateSellValueOptimized(consolidatedItems, spawner); } finally { spawner.getLock().unlock(); } } + /** + * Calculates the total sell value of items using cached accumulated value + * This method is optimized to use pre-calculated sell values + */ + private SellResult calculateSellValueOptimized(Map consolidatedItems, + SpawnerData spawner) { + // Use the accumulated sell value from spawner (already calculated incrementally) + double totalValue = spawner.getAccumulatedSellValue(); + long totalItemsSold = 0; + List itemsToRemove = new ArrayList<>(); + + // We still need to create the items list for removal + for (Map.Entry entry : consolidatedItems.entrySet()) { + ItemStack template = entry.getKey().getTemplate(); + long amount = entry.getValue(); + + // Count items (we need this even if we skip price calculation) + totalItemsSold += amount; + + // Create ItemStacks to remove (handle stacking properly) + long remainingAmount = amount; + while (remainingAmount > 0) { + ItemStack stackToRemove = template.clone(); + int stackSize = (int) Math.min(remainingAmount, template.getMaxStackSize()); + stackToRemove.setAmount(stackSize); + itemsToRemove.add(stackToRemove); + remainingAmount -= stackSize; + } + } + + return new SellResult(totalValue, totalItemsSold, itemsToRemove); + } + /** * Calculates the total sell value of items asynchronously * This method processes large inventories efficiently without blocking diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerFileHandler.java b/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerFileHandler.java index 02d01382..f683b43a 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerFileHandler.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerFileHandler.java @@ -407,6 +407,9 @@ private SpawnerData loadSpawnerFromConfig(String spawnerId, boolean logErrors) { spawner.setVirtualInventory(virtualInv); + // Recalculate accumulated sell value after loading inventory + spawner.recalculateSellValue(); + // Load last interacted player String lastInteractedPlayer = spawnerData.getString(path + ".lastInteractedPlayer"); spawner.setLastInteractedPlayer(lastInteractedPlayer); diff --git a/core/src/main/resources/language/DonutSMP/gui.yml b/core/src/main/resources/language/DonutSMP/gui.yml index 6f6ad660..c73b96de 100644 --- a/core/src/main/resources/language/DonutSMP/gui.yml +++ b/core/src/main/resources/language/DonutSMP/gui.yml @@ -34,10 +34,12 @@ spawner_info_item: - '&#FCE300● &fClick to sell items and collect xp' - '&#FCE300Storage:&f %formatted_storage%% &#FCE300Filled.' - '&#FCE300Exp:&f %formatted_exp%% &#FCE300Stored.' + - '&#FCE300Sellable: +&a%total_sell_price%' lore_no_shop: - '&#FCE300● &fClick to collect xp' - '&#FCE300Storage:&f %formatted_storage%% &#FCE300Filled.' - '&#FCE300Exp:&f %formatted_exp%% &#FCE300Stored.' + - '&#FCE300Sellable: +&a%total_sell_price%' lore_full: '' lore_inactive: '' @@ -97,7 +99,7 @@ navigation_button_next: - '&fClick to go forward a page' sell_button: - name: '�F986ꜱᴇʟʟ ᴀʟʟ' + name: '�F986ꜱᴇʟʟ ᴀʟʟ: +&a%total_sell_price%' lore: - '&fClick to sell all mob drops' diff --git a/core/src/main/resources/language/de_DE/gui.yml b/core/src/main/resources/language/de_DE/gui.yml index 55073ec3..aa54e84b 100644 --- a/core/src/main/resources/language/de_DE/gui.yml +++ b/core/src/main/resources/language/de_DE/gui.yml @@ -99,6 +99,7 @@ spawner_info_item: - ' &#bdc3c7• ᴍᴏʙꜱ: ඪdb%min_mobs% &#bdc3c7- ඪdb%max_mobs%' - ' &#bdc3c7• ᴠᴇʀᴢᴏᴇɢᴇʀᴜɴɢ: ඪdb%delay% &#bdc3c7ꜱ' - ' &#bdc3c7• ɴᴀᴇᴄʜꜱᴛᴇʀ ꜱᴘᴀᴡɴ: ඪdb%time%' + - ' &#bdc3c7• ᴠᴇʀᴋᴀᴜꜰʙᴀʀ: +&a%total_sell_price%' - '' - 'ඪdb⊳ &#ecf0f1ʀᴇᴄʜᴛꜱᴋʟɪᴄᴋ ᴢᴜᴍ ᴏᴇꜰꜰɴᴇɴ ᴅᴇʀ ඪdbꜱᴛᴀᴄᴋᴇʀ ɢᴜɪ' - 'ඪdb⊳ &#ecf0f1ᴋʟɪᴄᴋᴇɴ ᴢᴜᴍ &#e67e22ᴠᴇʀᴋᴀᴜꜰᴇɴ &#ecf0f1& ecc71xᴘ ᴇɪɴꜱᴀᴍᴍᴇʟɴ' @@ -111,6 +112,7 @@ spawner_info_item: - ' &#bdc3c7• ᴍᴏʙꜱ: ඪdb%min_mobs% &#bdc3c7- ඪdb%max_mobs%' - ' &#bdc3c7• ᴠᴇʀᴢᴏᴇɢᴇʀᴜɴɢ: ඪdb%delay% &#bdc3c7ꜱ' - ' &#bdc3c7• ɴᴀᴇᴄʜꜱᴛᴇʀ ꜱᴘᴀᴡɴ: ඪdb%time%' + - ' &#bdc3c7• ᴠᴇʀᴋᴀᴜꜰʙᴀʀ: +&a%total_sell_price%' - '' - 'ඪdb⊳ &#ecf0f1ᴋʟɪᴄᴋᴇɴ ᴢᴜᴍ ᴏᴇꜰꜰɴᴇɴ ᴅᴇʀ ඪdbꜱᴛᴀᴄᴋᴇʀ ɢᴜɪ' @@ -178,7 +180,7 @@ navigation_button_next: - 'cc483⊳ &#f8f8ffᴋʟɪᴄᴋᴇɴ ᴜᴍ ᴢᴜ ꜱᴇɪᴛᴇ %eb9a%target_page% &#f8f8ffᴢᴜ ɢᴇʜᴇɴ' sell_button: - name: '&aᴀʟʟᴇ ɪᴛᴇᴍꜱ ᴠᴇʀᴋᴀᴜꜰᴇɴ' + name: '&aᴀʟʟᴇ ɪᴛᴇᴍꜱ ᴠᴇʀᴋᴀᴜꜰᴇɴ: +&a%total_sell_price%' lore: - '&a⊳ &#f8f8ffᴋʟɪᴄᴋᴇɴ ᴜᴍ ᴀʟʟᴇ ɪᴛᴇᴍꜱ ᴢᴜ ᴠᴇʀᴋᴀᴜꜰᴇɴ' diff --git a/core/src/main/resources/language/en_US/gui.yml b/core/src/main/resources/language/en_US/gui.yml index 4eb24730..d6f6a4e6 100644 --- a/core/src/main/resources/language/en_US/gui.yml +++ b/core/src/main/resources/language/en_US/gui.yml @@ -99,6 +99,7 @@ spawner_info_item: - ' &#bdc3c7• ᴍᴏʙꜱ: ඪdb%min_mobs% &#bdc3c7- ඪdb%max_mobs%' - ' &#bdc3c7• ᴅᴇʟᴀʏ: ඪdb%delay% &#bdc3c7ꜱ' - ' &#bdc3c7• ɴᴇxᴛ ꜱᴘᴀᴡɴ: ඪdb%time%' + - ' &#bdc3c7• ꜱᴇʟʟᴀʙʟᴇ: +&a%total_sell_price%' - '' - 'ඪdb⊳ &#ecf0f1ʀɪɢʜᴛ-ᴄʟɪᴄᴋ ᴛᴏ ᴏᴘᴇɴ ඪdbꜱᴛᴀᴄᴋᴇʀ ɢᴜɪ' - 'ඪdb⊳ &#ecf0f1ᴄʟɪᴄᴋ ᴛᴏ &#e67e22ꜱᴇʟʟ ɪᴛᴇᴍꜱ &#ecf0f1& ecc71ᴄᴏʟʟᴇᴄᴛ xᴘ' @@ -111,6 +112,7 @@ spawner_info_item: - ' &#bdc3c7• ᴍᴏʙꜱ: ඪdb%min_mobs% &#bdc3c7- ඪdb%max_mobs%' - ' &#bdc3c7• ᴅᴇʟᴀʏ: ඪdb%delay% &#bdc3c7ꜱ' - ' &#bdc3c7• ɴᴇxᴛ ꜱᴘᴀᴡɴ: ඪdb%time%' + - ' &#bdc3c7• ꜱᴇʟʟᴀʙʟᴇ: +&a%total_sell_price%' - '' - 'ඪdb⊳ &#ecf0f1ᴄʟɪᴄᴋ ᴛᴏ ᴏᴘᴇɴ ඪdbꜱᴛᴀᴄᴋᴇʀ ɢᴜɪ' @@ -178,7 +180,7 @@ navigation_button_next: - 'cc483⊳ &#f8f8ffᴄʟɪᴄᴋ ᴛᴏ ɢᴏ ᴛᴏ ᴘᴀɢᴇ %eb9a%target_page%' sell_button: - name: '&aꜱᴇʟʟ ᴀʟʟ ɪᴛᴇᴍꜱ' + name: '&aꜱᴇʟʟ ᴀʟʟ ɪᴛᴇᴍꜱ: +&a%total_sell_price%' lore: - '&a⊳ &#f8f8ffᴄʟɪᴄᴋ ᴛᴏ ꜱᴇʟʟ ᴀʟʟ ɪᴛᴇᴍꜱ' diff --git a/core/src/main/resources/language/vi_VN/gui.yml b/core/src/main/resources/language/vi_VN/gui.yml index 98123ecf..0a3799b4 100644 --- a/core/src/main/resources/language/vi_VN/gui.yml +++ b/core/src/main/resources/language/vi_VN/gui.yml @@ -67,6 +67,7 @@ spawner_info_item: - ' &#bdc3c7• số ᴍᴏʙ: ඪdb%min_mobs% &#bdc3c7- ඪdb%max_mobs%' - ' &#bdc3c7• ᴛʜờɪ ɢɪᴀɴ: ඪdb%delay% &#bdc3c7ɢɪâʏ' - ' &#bdc3c7• ʟầɴ sᴘᴀᴡɴ ᴛɪếᴘ: ඪdb%time%' + - ' &#bdc3c7• ɢɪá ʙáɴ: +&a%total_sell_price%' - '' - 'ඪdb⊳ &#ecf0f1ᴄʜᴜộᴛ ᴘʜảɪ ᴍở ඪdbɢɪᴀᴏ ᴅɪệɴ ꜱᴛᴀᴄᴋᴇʀ' - 'ඪdb⊳ &#ecf0f1ɴʜấᴘ để &#e67e22ʙáɴ ᴠậᴛ ᴘʜẩᴍ &#ecf0f1& ecc71ɴʜậɴ xᴘ' @@ -79,6 +80,7 @@ spawner_info_item: - ' &#bdc3c7• số ᴍᴏʙ: ඪdb%min_mobs% &#bdc3c7- ඪdb%max_mobs%' - ' &#bdc3c7• ᴛʜờɪ ɢɪᴀɴ: ඪdb%delay% &#bdc3c7ɢɪâʏ' - ' &#bdc3c7• ʟầɴ sᴘᴀᴡɴ ᴛɪếᴘ: ඪdb%time%' + - ' &#bdc3c7• ɢɪá ʙáɴ: +&a%total_sell_price%' - '' - 'ඪdb⊳ &#ecf0f1ᴄʜᴜộᴛ ᴘʜảɪ ᴍở ඪdbɢɪᴀᴏ ᴅɪệɴ ꜱᴛᴀᴄᴋᴇʀ' @@ -146,7 +148,7 @@ navigation_button_next: - 'cc483⊳ &#f8f8ffɴʜấᴘ để đếɴ ᴛʀᴀɴɢ %eb9a%target_page%' sell_button: - name: '&aʙáɴ ᴠậᴛ ᴘʜẩᴍ' + name: '&aʙáɴ ᴠậᴛ ᴘʜẩᴍ: +&a%total_sell_price%' lore: - '&a⊳ &#f8f8ffɴʜấᴘ để ʙáɴ ᴛấᴛ ᴄả ᴠậᴛ ᴘʜẩᴍ'