diff --git a/pom.xml b/pom.xml index 73b620d..0c0aefa 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ 2.0.9 1.21.3-R0.1-SNAPSHOT - 3.2.4-SNAPSHOT + 3.2.5-SNAPSHOT 1.12.0 @@ -67,7 +67,7 @@ -LOCAL - 2.18.0 + 2.19.0 BentoBoxWorld_Level bentobox-world https://sonarcloud.io @@ -158,6 +158,11 @@ songoda-plugins https://repo.songoda.com/repository/minecraft-plugins/ + + + matteodev + https://maven.devs.beer/ + @@ -245,6 +250,13 @@ 1.0.0-20240329.173606-35 provided + + + dev.lone + api-itemsadder + 4.0.2-beta-release-11 + provided + diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java index 5e66c27..d1b1d36 100644 --- a/src/main/java/world/bentobox/level/Level.java +++ b/src/main/java/world/bentobox/level/Level.java @@ -98,79 +98,98 @@ private boolean loadSettings() { @Override public void onEnable() { - loadBlockSettings(); - // Start pipeline - pipeliner = new Pipeliner(this); - // Start Manager - manager = new LevelsManager(this); - // Register listeners - this.registerListener(new IslandActivitiesListeners(this)); - this.registerListener(new JoinLeaveListener(this)); - this.registerListener(new MigrationListener(this)); - - // Register commands for GameModes - registeredGameModes.clear(); - getPlugin().getAddonsManager().getGameModeAddons().stream() - .filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> { - log("Level hooking into " + gm.getDescription().getName()); - registerCommands(gm); - new PlaceholderManager(this).registerPlaceholders(gm); - registeredGameModes.add(gm); - }); - // Register request handlers - registerRequestHandler(new LevelRequestHandler(this)); - registerRequestHandler(new TopTenRequestHandler(this)); - - // Check if WildStackers is enabled on the server - // I only added support for counting blocks into the island level - // Someone else can PR if they want spawners added to the Leveling system :) - if (!settings.getDisabledPluginHooks().contains("WildStacker")) { - stackersEnabled = Bukkit.getPluginManager().isPluginEnabled("WildStacker"); - if (stackersEnabled) { - log("Hooked into WildStackers."); - } - } - - // Check if AdvancedChests is enabled on the server - if (!settings.getDisabledPluginHooks().contains("AdvancedChests")) { - Plugin advChest = Bukkit.getPluginManager().getPlugin("AdvancedChests"); - advChestEnabled = advChest != null; - if (advChestEnabled) { - // Check version - if (compareVersions(advChest.getDescription().getVersion(), "23.0") > 0) { - log("Hooked into AdvancedChests."); - } else { - logError("Could not hook into AdvancedChests " + advChest.getDescription().getVersion() - + " - requires version 23.0 or later"); - advChestEnabled = false; - } - } - } - - // Check if RoseStackers is enabled - if (!settings.getDisabledPluginHooks().contains("RoseStacker")) { - roseStackersEnabled = Bukkit.getPluginManager().isPluginEnabled("RoseStacker"); - if (roseStackersEnabled) { - log("Hooked into RoseStackers."); - } - } - - // Check if UltimateStacker is enabled - if (!settings.getDisabledPluginHooks().contains("UltimateStacker")) { - ultimateStackerEnabled = Bukkit.getPluginManager().isPluginEnabled("UltimateStacker"); - if (ultimateStackerEnabled) { - log("Hooked into UltimateStacker."); - } - } - } - - @Override - public void allLoaded() { - super.allLoaded(); - - if (this.isEnabled()) { - this.hookExtensions(); - } + // Everything waits until allLoaded + } + + @Override + public void allLoaded() { + super.allLoaded(); + loadBlockSettings(); + initializePipelineAndManager(); + registerAllListeners(); + registerGameModeCommands(); + registerRequestHandlers(); + hookPlugin("WildStacker", this::hookWildStackers); + hookAdvancedChests(); + hookPlugin("RoseStacker", this::hookRoseStackers); + hookPlugin("UltimateStacker", this::hookUltimateStacker); + + if (this.isEnabled()) { + hookExtensions(); + } + } + + private void initializePipelineAndManager() { + pipeliner = new Pipeliner(this); + manager = new LevelsManager(this); + } + + private void registerAllListeners() { + registerListener(new IslandActivitiesListeners(this)); + registerListener(new JoinLeaveListener(this)); + registerListener(new MigrationListener(this)); + } + + private void registerGameModeCommands() { + registeredGameModes.clear(); + getPlugin().getAddonsManager().getGameModeAddons().stream() + .filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> { + log("Level hooking into " + gm.getDescription().getName()); + registerCommands(gm); + new PlaceholderManager(this).registerPlaceholders(gm); + registeredGameModes.add(gm); + }); + } + + private void registerRequestHandlers() { + registerRequestHandler(new LevelRequestHandler(this)); + registerRequestHandler(new TopTenRequestHandler(this)); + } + + /** + * A helper that only executes the provided hookAction if the plugin is not disabled. + */ + private void hookPlugin(String pluginName, Runnable hookAction) { + if (!settings.getDisabledPluginHooks().contains(pluginName)) { + hookAction.run(); + } + } + + private void hookWildStackers() { + stackersEnabled = Bukkit.getPluginManager().isPluginEnabled("WildStacker"); + if (stackersEnabled) { + log("Hooked into WildStackers."); + } + } + + private void hookAdvancedChests() { + if (!settings.getDisabledPluginHooks().contains("AdvancedChests")) { + Plugin advChest = Bukkit.getPluginManager().getPlugin("AdvancedChests"); + advChestEnabled = advChest != null; + if (advChestEnabled) { + if (compareVersions(advChest.getDescription().getVersion(), "23.0") > 0) { + log("Hooked into AdvancedChests."); + } else { + logError("Could not hook into AdvancedChests " + advChest.getDescription().getVersion() + + " - requires version 23.0 or later"); + advChestEnabled = false; + } + } + } + } + + private void hookRoseStackers() { + roseStackersEnabled = Bukkit.getPluginManager().isPluginEnabled("RoseStacker"); + if (roseStackersEnabled) { + log("Hooked into RoseStackers."); + } + } + + private void hookUltimateStacker() { + ultimateStackerEnabled = Bukkit.getPluginManager().isPluginEnabled("UltimateStacker"); + if (ultimateStackerEnabled) { + log("Hooked into UltimateStacker."); + } } /** @@ -448,4 +467,8 @@ public Warp getWarpHook() { return this.warpHook; } + public boolean isItemsAdder() { + return getPlugin().getHooks().getHook("ItemsAdder").isPresent(); + } + } diff --git a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java index bcaf620..9188594 100644 --- a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java +++ b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java @@ -48,10 +48,12 @@ import us.lynuxcraft.deadsilenceiv.advancedchests.chest.gui.page.ChestPage; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.bentobox.util.Pair; import world.bentobox.bentobox.util.Util; import world.bentobox.level.Level; import world.bentobox.level.calculators.Results.Result; +import world.bentobox.level.config.BlockConfig; public class IslandLevelCalculator { private static final String LINE_BREAK = "=================================="; @@ -133,6 +135,24 @@ private long calculateLevel(long blockAndDeathPoints) { } } + /** + * Adds value to the results based on the namespacedId and whether the block is + * below sea level or not + * + * @param namespacedId - namespacedId of the block + * @param belowSeaLevel - true if below sea level + */ + private void checkBlock(String namespacedId, boolean belowSeaLevel) { + int count = limitCountAndValue(namespacedId); + if (belowSeaLevel) { + results.underWaterBlockCount.addAndGet(count); + results.uwCount.add(namespacedId); + } else { + results.rawBlockCount.addAndGet(count); + results.mdCount.add(namespacedId); + } + } + /** * Adds value to the results based on the material and whether the block is * below sea level or not @@ -141,7 +161,7 @@ private long calculateLevel(long blockAndDeathPoints) { * @param belowSeaLevel - true if below sea level */ private void checkBlock(Material mat, boolean belowSeaLevel) { - int count = limitCount(mat); + int count = limitCountAndValue(mat); if (belowSeaLevel) { results.underWaterBlockCount.addAndGet(count); results.uwCount.add(mat); @@ -159,7 +179,7 @@ private void checkBlock(Material mat, boolean belowSeaLevel) { * @param belowSeaLevel - true if below sea level */ private void checkSpawner(EntityType et, boolean belowSeaLevel) { - Integer count = limitCount(et); + Integer count = limitCountAndValue(et); if (count != null) { if (belowSeaLevel) { results.underWaterBlockCount.addAndGet(count); @@ -263,14 +283,14 @@ public Results getResults() { /** * Get value of a material World blocks trump regular block values * - * @param md - Material or EntityType to check + * @param obj - Material, EntityType, or NamespacedId to check * @return value */ - private int getValue(Object md) { - Integer value = addon.getBlockConfig().getValue(island.getWorld(), md); + private int getValue(Object obj) { + Integer value = addon.getBlockConfig().getValue(island.getWorld(), obj); if (value == null) { // Not in config - results.ncCount.add(md); + results.ncCount.add(obj); return 0; } return value; @@ -334,19 +354,21 @@ private void roseStackerCheck(Chunk chunk) { * @param obj A Material or EntityType * @return The object's value if within limit, otherwise 0. */ - private int limitCount(Object obj) { + private int limitCountAndValue(Object obj) { // Only process if obj is a Material or EntityType - if (!(obj instanceof Material) && !(obj instanceof EntityType)) + if (!(obj instanceof Material) && !(obj instanceof EntityType) && !(obj instanceof String)) { return 0; + } Integer limit = addon.getBlockConfig().getLimit(obj); - if (limit == null) + if (limit == null) { return getValue(obj); + } int count = limitCount.getOrDefault(obj, 0); - if (count > limit) + if (count > limit) { return 0; - + } limitCount.put(obj, count + 1); return getValue(obj); } @@ -427,68 +449,87 @@ private CompletableFuture scanChunk(List chunks) { record ChunkPair(World world, Chunk chunk, ChunkSnapshot chunkSnapshot) { } - /** - * Count the blocks on the island - * - * @param cp chunk to scan - */ private void scanAsync(ChunkPair cp) { + int chunkX = cp.chunkSnapshot.getX() * 16; + int chunkZ = cp.chunkSnapshot.getZ() * 16; + int minX = island.getMinProtectedX(); + int maxX = minX + island.getProtectionRange() * 2; + int minZ = island.getMinProtectedZ(); + int maxZ = minZ + island.getProtectionRange() * 2; + for (int x = 0; x < 16; x++) { - // Check if the block coordinate is inside the protection zone and if not, don't - // count it - if (cp.chunkSnapshot.getX() * 16 + x < island.getMinProtectedX() || cp.chunkSnapshot.getX() * 16 - + x >= island.getMinProtectedX() + island.getProtectionRange() * 2) { - continue; - } - for (int z = 0; z < 16; z++) { - // Check if the block coordinate is inside the protection zone and if not, don't - // count it - if (cp.chunkSnapshot.getZ() * 16 + z < island.getMinProtectedZ() || cp.chunkSnapshot.getZ() * 16 - + z >= island.getMinProtectedZ() + island.getProtectionRange() * 2) { - continue; - } - // Only count to the highest block in the world for some optimization - for (int y = cp.world.getMinHeight(); y < cp.world.getMaxHeight(); y++) { - BlockData blockData = cp.chunkSnapshot.getBlockData(x, y, z); - Material m = blockData.getMaterial(); - boolean belowSeaLevel = seaHeight > 0 && y <= seaHeight; - Location loc = new Location(cp.world, (double) x + cp.chunkSnapshot.getX() * 16, y, - (double) z + cp.chunkSnapshot.getZ() * 16); - // Slabs can be doubled, so check them twice - if (Tag.SLABS.isTagged(m)) { - Slab slab = (Slab) blockData; - if (slab.getType().equals(Slab.Type.DOUBLE)) { - checkBlock(m, belowSeaLevel); + int globalX = chunkX + x; + if (globalX >= minX && globalX < maxX) { + for (int z = 0; z < 16; z++) { + int globalZ = chunkZ + z; + if (globalZ >= minZ && globalZ < maxZ) { + for (int y = cp.world.getMinHeight(); y < cp.world.getMaxHeight(); y++) { + processBlock(cp, x, y, z, globalX, globalZ); } } - // Hook for Wild Stackers (Blocks and Spawners Only) - this has to use the real - // chunk - if (addon.isStackersEnabled() && (m.equals(Material.CAULDRON) || m.equals(Material.SPAWNER))) { - stackedBlocks.add(loc); - } + } + } + } + } - if (addon.isUltimateStackerEnabled() && !m.isAir()) { - UltimateStackerCalc.addStackers(m, loc, results, belowSeaLevel, limitCount(m)); - } + private void processBlock(ChunkPair cp, int x, int y, int z, int globalX, int globalZ) { + BlockData blockData = cp.chunkSnapshot.getBlockData(x, y, z); + Material m = blockData.getMaterial(); + if (m.isAir()) { + return; + } - // Scan chests - if (addon.getSettings().isIncludeChests() && blockData instanceof Container) { - chestBlocks.add(cp.chunk); - } + boolean belowSeaLevel = seaHeight > 0 && y <= seaHeight; + Location loc = new Location(cp.world, globalX, y, globalZ); - // Spawners - if (m == Material.SPAWNER) { - // Stash the spawner because the type cannot be obtained from the chunk snapshot - this.spawners.put(loc, belowSeaLevel); - } else { - // Add the value of the block's material - checkBlock(m, belowSeaLevel); - } - } + String customRegionId = addon.isItemsAdder() ? ItemsAdderHook.getInCustomRegion(loc) : null; + if (customRegionId != null) { + checkBlock(customRegionId, belowSeaLevel); + return; + } + + processSlabs(blockData, m, belowSeaLevel); + processStackers(loc, m); + processUltimateStacker(m, loc, belowSeaLevel); + processChests(cp, blockData); + processSpawnerOrBlock(m, loc, belowSeaLevel); + } + + private void processSlabs(BlockData blockData, Material m, boolean belowSeaLevel) { + if (Tag.SLABS.isTagged(m)) { + Slab slab = (Slab) blockData; + if (slab.getType().equals(Slab.Type.DOUBLE)) { + checkBlock(m, belowSeaLevel); } } } + private void processStackers(Location loc, Material m) { + if (addon.isStackersEnabled() && (m.equals(Material.CAULDRON) || m.equals(Material.SPAWNER))) { + stackedBlocks.add(loc); + } + } + + private void processUltimateStacker(Material m, Location loc, boolean belowSeaLevel) { + if (addon.isUltimateStackerEnabled() && !m.isAir()) { + UltimateStackerCalc.addStackers(m, loc, results, belowSeaLevel, limitCountAndValue(m)); + } + } + + private void processChests(ChunkPair cp, BlockData blockData) { + if (addon.getSettings().isIncludeChests() && blockData instanceof Container) { + chestBlocks.add(cp.chunk); + } + } + + private void processSpawnerOrBlock(Material m, Location loc, boolean belowSeaLevel) { + if (m == Material.SPAWNER) { + spawners.put(loc, belowSeaLevel); + } else { + checkBlock(m, belowSeaLevel); + } + } + /** * Scan the next chunk on the island * @@ -536,11 +577,14 @@ private Collection sortedReport(int total, Multiset uwCount) { value = Objects.requireNonNullElse(addon.getBlockConfig().getValue(island.getWorld(), md), 0); name = Util.prettifyText(md.name()); } else if (en.getElement() instanceof EntityType et) { - name = Util.prettifyText(et.name()); + name = Util.prettifyText(et.name() + BlockConfig.SPAWNER); value = Objects.requireNonNullElse(addon.getBlockConfig().getValue(island.getWorld(), et), 0); + } else if (en.getElement() instanceof String str) { + name = str; + value = Objects.requireNonNullElse(addon.getBlockConfig().getValue(island.getWorld(), str), 0); } - result.add(name + " :" + String.format("%,d", en.getCount()) + " blocks x " + value + " = " + result.add(name + ": " + String.format("%,d", en.getCount()) + " blocks x " + value + " = " + (value * en.getCount())); total += (value * en.getCount()); diff --git a/src/main/java/world/bentobox/level/commands/IslandValueCommand.java b/src/main/java/world/bentobox/level/commands/IslandValueCommand.java index 9e3c4f5..1b8e22a 100644 --- a/src/main/java/world/bentobox/level/commands/IslandValueCommand.java +++ b/src/main/java/world/bentobox/level/commands/IslandValueCommand.java @@ -7,12 +7,14 @@ import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.eclipse.jdt.annotation.NonNull; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.bentobox.util.Util; import world.bentobox.level.Level; import world.bentobox.level.objects.IslandLevels; @@ -44,76 +46,76 @@ public void setup() @Override - public boolean execute(User user, String label, List args) - { - if (args.size() > 1) - { - this.showHelp(this, user); + public boolean execute(User user, String label, List args) { + if (args.size() > 1) { + showHelp(this, user); return false; } - if (args.isEmpty()) - { - ValuePanel.openPanel(this.addon, this.getWorld(), user); + if (args.isEmpty()) { + ValuePanel.openPanel(addon, getWorld(), user); + return true; } - else if (args.get(0).equalsIgnoreCase("HAND")) - { - Player player = user.getPlayer(); - PlayerInventory inventory = player.getInventory(); - if (!inventory.getItemInMainHand().getType().equals(Material.AIR)) - { - this.printValue(user, inventory.getItemInMainHand().getType()); - } - else - { - Utils.sendMessage(user, user.getTranslation("level.conversations.empty-hand")); - } + String arg = args.get(0); + if ("HAND".equalsIgnoreCase(arg)) { + executeHandCommand(user); + return true; } - else - { - Material material = Material.matchMaterial(args.get(0)); - if (material == null) - { - Utils.sendMessage(user, - user.getTranslation(this.getWorld(), "level.conversations.unknown-item", - MATERIAL, args.get(0))); - } - else - { - this.printValue(user, material); + executeMaterialCommand(user, arg); + return true; + } + + private void executeHandCommand(User user) { + Player player = user.getPlayer(); + PlayerInventory inventory = player.getInventory(); + ItemStack mainHandItem = inventory.getItemInMainHand(); + + if (mainHandItem.getType() == Material.AIR) { + Utils.sendMessage(user, user.getTranslation("level.conversations.empty-hand")); + return; + } + + if (addon.isItemsAdder()) { + Optional id = ItemsAdderHook.getNamespacedId(mainHandItem); + if (id.isPresent()) { + printValue(user, id.get()); + return; } } - return true; + printValue(user, mainHandItem.getType()); } + private void executeMaterialCommand(User user, String arg) { + Material material = Material.matchMaterial(arg); + if (material == null) { + Utils.sendMessage(user, user.getTranslation(getWorld(), "level.conversations.unknown-item", MATERIAL, arg)); + } else { + printValue(user, material); + } + } /** * This method prints value of the given material in chat. * @param user User who receives the message. * @param material Material value. */ - private void printValue(User user, Material material) + private void printValue(User user, Object material) { Integer value = this.addon.getBlockConfig().getValue(getWorld(), material); if (value != null) { - Utils.sendMessage(user, - user.getTranslation(this.getWorld(), "level.conversations.value", - "[value]", String.valueOf(value), - MATERIAL, Utils.prettifyObject(material, user))); + Utils.sendMessage(user, user.getTranslation(this.getWorld(), "level.conversations.value", "[value]", + String.valueOf(value), MATERIAL, Utils.prettifyObject(material, user))); double underWater = this.addon.getSettings().getUnderWaterMultiplier(); - if (underWater > 1.0) - { - Utils.sendMessage(user, - user.getTranslation(this.getWorld(),"level.conversations.success-underwater", - "[value]", (underWater * value) + ""), - MATERIAL, Utils.prettifyObject(material, user)); + if (underWater > 1.0) { + Utils.sendMessage(user, user.getTranslation(this.getWorld(), "level.conversations.success-underwater", + "[value]", (underWater * value) + ""), MATERIAL, Utils.prettifyObject(material, user)); } // Show how many have been placed and how many are allowed @@ -121,25 +123,19 @@ private void printValue(User user, Material material) IslandLevels lvData = this.addon.getManager() .getLevelsData(getIslands().getPrimaryIsland(getWorld(), user.getUniqueId())); int count = lvData.getMdCount().getOrDefault(material, 0) + lvData.getUwCount().getOrDefault(material, 0); - user.sendMessage("level.conversations.you-have", TextVariables.NUMBER, - String.valueOf(count)); + user.sendMessage("level.conversations.you-have", TextVariables.NUMBER, String.valueOf(count)); Integer limit = this.addon.getBlockConfig().getLimit(material); if (limit != null) { - user.sendMessage("level.conversations.you-can-place", TextVariables.NUMBER, - String.valueOf(limit)); + user.sendMessage("level.conversations.you-can-place", TextVariables.NUMBER, String.valueOf(limit)); } } - else - { - Utils.sendMessage(user, - user.getTranslation(this.getWorld(),"level.conversations.no-value")); + else { + Utils.sendMessage(user, user.getTranslation(this.getWorld(), "level.conversations.no-value")); } } - @Override - public Optional> tabComplete(User user, String alias, List args) - { + public Optional> tabComplete(User user, String alias, List args) { String lastArg = !args.isEmpty() ? args.get(args.size() - 1) : ""; if (args.isEmpty()) @@ -148,9 +144,8 @@ public Optional> tabComplete(User user, String alias, List return Optional.empty(); } - List options = new ArrayList<>(Arrays.stream(Material.values()). - filter(Material::isBlock). - map(Material::name).toList()); + List options = new ArrayList<>( + Arrays.stream(Material.values()).filter(Material::isBlock).map(Material::name).toList()); options.add("HAND"); diff --git a/src/main/java/world/bentobox/level/config/BlockConfig.java b/src/main/java/world/bentobox/level/config/BlockConfig.java index 4ac7e76..7cfecec 100644 --- a/src/main/java/world/bentobox/level/config/BlockConfig.java +++ b/src/main/java/world/bentobox/level/config/BlockConfig.java @@ -10,13 +10,16 @@ import java.util.Objects; import org.bukkit.Bukkit; +import org.bukkit.Keyed; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.EntityType; +import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.level.Level; /** @@ -26,129 +29,150 @@ */ public class BlockConfig { - private static final String SPAWNER = "_SPAWNER"; + public static final String SPAWNER = "_spawner"; private Map blockLimits = new HashMap<>(); - private Map blockValues = new EnumMap<>(Material.class); - private final Map> worldBlockValues = new HashMap<>(); + private Map blockValues = new HashMap<>(); + private final Map> worldBlockValues = new HashMap<>(); private final Map> worldSpawnerValues = new HashMap<>(); - private final List hiddenBlocks; + private final List hiddenBlocks; private Map spawnerValues = new EnumMap<>(EntityType.class); private Level addon; /** * Loads block limits, values and world settings and then saves them again * @param addon - addon - * @param blockValues - yaml configuration file containing the block values + * @param blockValuesConfig - yaml configuration file containing the block values * @param file - the file representing the yaml config. Will be saved after readong. * @throws IOException - if there is an error */ - public BlockConfig(Level addon, YamlConfiguration blockValues, File file) throws IOException { + public BlockConfig(Level addon, YamlConfiguration blockValuesConfig, File file) throws IOException { this.addon = addon; - if (blockValues.isConfigurationSection("limits")) { - for (String key : blockValues.getConfigurationSection("limits").getKeys(false)) { - blockLimits.put(key, blockValues.getConfigurationSection("limits").getInt(key)); + if (blockValuesConfig.isConfigurationSection("limits")) { + ConfigurationSection limits = blockValuesConfig.getConfigurationSection("limits"); + for (String key : limits.getKeys(false)) { + // Convert old materials to namespaced keys + key = convertKey(limits, key); + blockLimits.put(key, limits.getInt(key)); } } - if (blockValues.isConfigurationSection("blocks")) { - setBlockValues(loadBlockValues(blockValues)); - setSpawnerValues(loadSpawnerValues(blockValues)); - } else { - addon.logWarning("No block values in blockconfig.yml! All island levels will be zero!"); + // The blocks section can include blocks, spawners, and namespacedIDs + if (blockValuesConfig.isConfigurationSection("blocks")) { + ConfigurationSection blocks = blockValuesConfig.getConfigurationSection("blocks"); + for (String key : blocks.getKeys(false)) { + // Convert old materials to namespaced keys + key = convertKey(blocks, key); + // Validate + if (isMaterial(key) || isSpawner(key) || isOther(key)) { + // Store for lookup + this.blockValues.put(key, blocks.getInt(key)); + } else { + addon.logError("Unknown listing in blocks section: " + key); + } + } + // Add missing items to the list + addMissing(blocks); } + // Worlds - if (blockValues.isConfigurationSection("worlds")) { - loadWorlds(blockValues); + if (blockValuesConfig.isConfigurationSection("worlds")) { + loadWorlds(blockValuesConfig); } // Hidden - hiddenBlocks = blockValues.getStringList("hidden-blocks").stream().map(name -> { - try { - return Material.valueOf(name.toUpperCase(Locale.ENGLISH)); - - } catch (Exception e) { - return null; - } - }).filter(Objects::nonNull).toList(); + hiddenBlocks = blockValuesConfig.getStringList("hidden-blocks").stream().map(this::convert).toList(); + blockValuesConfig.set("hidden-blocks", hiddenBlocks); // Update // All done - blockValues.save(file); + blockValuesConfig.save(file); } - private void loadWorlds(YamlConfiguration blockValues2) { - ConfigurationSection worlds = Objects.requireNonNull(blockValues2.getConfigurationSection("worlds")); - for (String world : Objects.requireNonNull(worlds).getKeys(false)) { - World bWorld = Bukkit.getWorld(world); - if (bWorld != null) { - ConfigurationSection worldValues = worlds.getConfigurationSection(world); - for (String material : Objects.requireNonNull(worldValues).getKeys(false)) { - try { - Material mat = Material.valueOf(material); - Map values = worldBlockValues.getOrDefault(bWorld, - new EnumMap<>(Material.class)); - values.put(mat, worldValues.getInt(material)); - worldBlockValues.put(bWorld, values); - } catch (Exception e) { - addon.logError( - "Unknown material (" + material + ") in blockconfig.yml worlds section. Skipping..."); - } - } - } else { - addon.logWarning("Level Addon: No such world in blockconfig.yml : " + world); - } - } + private void addMissing(ConfigurationSection blocks) { + // Add missing materials + Registry.MATERIAL.stream() + .filter(m -> m.isBlock()).filter(m -> !m.isAir()) + .filter(m -> !blockValues.containsKey(m.getKey().getKey())) + .forEach(m -> blocks.set(m.getKey().getKey(), 1)); // Add a default value of 1 + // Add missing spawners + Registry.MATERIAL.stream().filter(Material::isItem).filter(m -> m.name().endsWith("_SPAWN_EGG")) // Get potential spawners by looking up spawn eggs, which are how a spawner can be set + .map(m -> m.getKey().getKey().substring(0, m.name().length() - 10) + SPAWNER) // Change the name of the egg to "entity-type_spawner" + .filter(s -> !this.blockValues.containsKey(s)) // Check if the blockValues map contains this spawner + .forEach(m -> blocks.set(m, 1)); // Add a default value of 1 + } + private boolean isOther(String key) { + // Maybe a custom name space + return ItemsAdderHook.isInRegistry(key); } - private Map loadBlockValues(YamlConfiguration blockValues2) { - ConfigurationSection blocks = Objects.requireNonNull(blockValues2.getConfigurationSection("blocks")); - Map bv = new EnumMap<>(Material.class); - // Update blockvalues to latest settings - Registry.MATERIAL.stream().filter(Material::isBlock) - .filter(m -> !m.name().startsWith("LEGACY_")) - .filter(m -> !m.isAir()) - .filter(m -> !m.equals(Material.WATER)) - .forEach(m -> { - if (!blocks.contains(m.name(), true)) { - blocks.set(m.name(), 1); - } - bv.put(m, blocks.getInt(m.name(), 1)); - }); - return bv; + private boolean isSpawner(String key) { + if (key.endsWith(SPAWNER)) { + // Spawner + String name = key.substring(0, key.length() - 8); + return Registry.ENTITY_TYPE.get(NamespacedKey.fromString(name)) != null; + } + return false; + } + + private boolean isMaterial(String key) { + return Registry.MATERIAL.get(NamespacedKey.fromString(key)) != null; } /** - * Loads the spawner values from the blocks in the config - * Format is entityname + _SPANWER, so for example ALLAY_SPAWNER - * If they are missing, then they will score 1 - * @param blockValues config section - * @return map of entity types and their score + * Converts old to new + * @param blocks + * @param key key + * @return new key */ - private Map loadSpawnerValues(YamlConfiguration blockValues) { - ConfigurationSection blocks = Objects.requireNonNull(blockValues.getConfigurationSection("blocks")); - Map bv = new HashMap<>(); + private String convertKey(ConfigurationSection blocks, String key) { + int value = blocks.getInt(key); + blocks.set(key, null); // Delete the old entry + key = convert(key); + blocks.set(key, value); // set the value + return key; + } + private String convert(String key) { + Material m = Material.getMaterial(key); + if (m != null) { + // Old material + key = m.getKey().getKey(); + } + // Convert old spawners + if (key.endsWith("_SPAWNER")) { + // Old spawner, convert to entity type name space + key = key.toLowerCase(Locale.ENGLISH); + } + return key; + } - // Update spawners - Registry.MATERIAL.stream().filter(Material::isItem) - .filter(m -> m.name().endsWith("_SPAWN_EGG")).map(m -> m.name().substring(0, m.name().length() - 10)) - .forEach(m -> { - // Populate missing spawners - if (!blocks.contains(m + SPAWNER, true)) { - blocks.set(m + SPAWNER, 1); + private void loadWorlds(YamlConfiguration blockValues2) { + ConfigurationSection worlds = Objects.requireNonNull(blockValues2.getConfigurationSection("worlds")); + for (String world : Objects.requireNonNull(worlds).getKeys(false)) { + World bWorld = Bukkit.getWorld(world); + if (bWorld != null) { + ConfigurationSection blocks = worlds.getConfigurationSection(world); + Map values = worldBlockValues.getOrDefault(bWorld, new HashMap<>()); + for (String key : blocks.getKeys(false)) { + // Convert old materials to namespaced keys + key = convertKey(blocks, key); + // Validate + if (isMaterial(key) || isSpawner(key) || isOther(key)) { + // Store for lookup + values.put(key, blocks.getInt(key)); + } else { + addon.logError("Unknown listing in blocks section: " + key); } - // Load value - try { - EntityType et = EntityType.valueOf(m); - bv.put(et, blocks.getInt(m + SPAWNER)); - } catch (Exception e) { - e.printStackTrace(); + } + worldBlockValues.put(bWorld, values); + } else { + addon.log("Level Addon: No such world in blockconfig.yml : " + world); } - }); - return bv; + } + } /** * Return the limits for any particular material or entity type - * @param obj material or entity type + * @param obj material, entity type, or namespacedId * @return the limit or null if there isn't one */ public Integer getLimit(Object obj) { @@ -158,27 +182,11 @@ public Integer getLimit(Object obj) { if (obj instanceof EntityType et) { return blockLimits.get(et.name().concat(SPAWNER)); } + if (obj instanceof String s) { + return blockLimits.get(s); + } return null; } - /** - * @return the blockValues - */ - public final Map getBlockValues() { - return blockValues; - } - /** - * @param blockValues2 the blockValues to set - */ - private void setBlockValues(Map blockValues2) { - this.blockValues = blockValues2; - } - - /** - * @return the worldBlockValues - */ - public Map> getWorldBlockValues() { - return worldBlockValues; - } /** * @return the worldSpawnerValues @@ -188,32 +196,40 @@ public Map> getWorldSpawnerValues() { } /** - * Get the value of of a spawner in world - * @param world - world - * @param obj - entity type that will spawn from this spawner or material - * @return value or null if not configured with a value + * Retrieves the value associated with a spawner in the specified world, + * using world-specific settings if available, or falling back to baseline values. + * + * @param world the world context + * @param obj the object representing the entity type or material + * @return the corresponding value, or null if no value is configured */ public Integer getValue(World world, Object obj) { - if (obj instanceof EntityType et) { - // Check world settings - if (getWorldSpawnerValues().containsKey(world) && getWorldSpawnerValues().get(world).containsKey(et)) { - return getWorldSpawnerValues().get(world).get(et); - } - // Check baseline - if (getSpawnerValues().containsKey(et)) { - return getSpawnerValues().get(et); - } - } else if (obj instanceof Material md) { - // Check world settings - if (getWorldBlockValues().containsKey(world) && getWorldBlockValues().get(world).containsKey(md)) { - return getWorldBlockValues().get(world).get(md); - } - // Check baseline - if (getBlockValues().containsKey(md)) { - return getBlockValues().get(md); + // Extract the key based on the type of obj + String key = switch (obj) { + case Keyed keyed -> keyed.getKey().getKey(); + case String str -> str; + default -> ""; + }; + + if (key.isEmpty()) { + return null; + } + + if (obj instanceof EntityType) { + key = key.concat(SPAWNER); + } + + // Try to get the world-specific value first + Map worldValues = getWorldBlockValues().get(world); + if (worldValues != null) { + Integer value = worldValues.get(key); + if (value != null) { + return value; } } - return null; + + // Fall back to the baseline value + return getBlockValues().get(key); } /** @@ -223,9 +239,9 @@ public Integer getValue(World world, Object obj) { */ public boolean isHiddenBlock(Object obj) { if (obj instanceof Material m) { - return hiddenBlocks.contains(m); + return hiddenBlocks.contains(m.name()); } - return hiddenBlocks.contains(Material.SPAWNER); + return hiddenBlocks.contains(Material.SPAWNER.name()); } /** @@ -235,9 +251,9 @@ public boolean isHiddenBlock(Object obj) { */ public boolean isNotHiddenBlock(Object obj) { if (obj instanceof Material m) { - return !hiddenBlocks.contains(m); + return !hiddenBlocks.contains(m.name()); } else { - return !hiddenBlocks.contains(Material.SPAWNER); + return !hiddenBlocks.contains(Material.SPAWNER.name()); } } @@ -255,4 +271,18 @@ public void setSpawnerValues(Map spawnerValues) { this.spawnerValues = spawnerValues; } + /** + * @return the blockValues + */ + public Map getBlockValues() { + return blockValues; + } + + /** + * @return the worldBlockValues + */ + public Map> getWorldBlockValues() { + return worldBlockValues; + } + } diff --git a/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java b/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java index 4a75f5c..8e6166d 100644 --- a/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java +++ b/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java @@ -1,5 +1,6 @@ package world.bentobox.level.listeners; +import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -40,7 +41,8 @@ public IslandActivitiesListeners(Level addon) { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onNewIsland(IslandCreatedEvent e) { if (addon.getSettings().isZeroNewIslandLevels()) { - zeroIsland(e.getIsland()); + // Wait a few seconds before performing the zero + Bukkit.getScheduler().runTaskLater(addon.getPlugin(), () -> zeroIsland(e.getIsland()), 150L); } } diff --git a/src/main/java/world/bentobox/level/objects/IslandLevels.java b/src/main/java/world/bentobox/level/objects/IslandLevels.java index 2a4f709..ffebd79 100644 --- a/src/main/java/world/bentobox/level/objects/IslandLevels.java +++ b/src/main/java/world/bentobox/level/objects/IslandLevels.java @@ -168,6 +168,8 @@ public long getMaxLevel() { * @return the uwCount */ public Map getUwCount() { + // Loaded objects come in as strings, so need to be converted to Material Or EntityTypes + uwCount = convertMap(uwCount); return uwCount; } @@ -176,9 +178,6 @@ public Map getUwCount() { * @param map the uwCount to set */ public void setUwCount(Map map) { - // Loaded objects come in as strings, so need to be converted to Material Or EntityTypes - uwCount = convertMap(uwCount); - this.uwCount = map; } @@ -192,15 +191,14 @@ public Map getMdCount() { return mdCount; } - private Map convertMap(Map mdCount) { + private Map convertMap(Map blockCountMap) { Map convertedMap = new HashMap<>(); - for (Map.Entry entry : mdCount.entrySet()) { + for (Map.Entry entry : blockCountMap.entrySet()) { Object key = entry.getKey(); Integer value = entry.getValue(); - if (key instanceof String) { - String keyStr = (String) key; + if (key instanceof String keyStr) { // First, try converting to Material Material material = Material.matchMaterial(keyStr); if (material != null) { diff --git a/src/main/java/world/bentobox/level/panels/DetailsPanel.java b/src/main/java/world/bentobox/level/panels/DetailsPanel.java index 0349e1a..366443c 100644 --- a/src/main/java/world/bentobox/level/panels/DetailsPanel.java +++ b/src/main/java/world/bentobox/level/panels/DetailsPanel.java @@ -28,6 +28,7 @@ import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.level.Level; import world.bentobox.level.objects.IslandLevels; import world.bentobox.level.util.Utils; @@ -218,10 +219,13 @@ private void updateFilters() { if (this.activeTab == Tab.SPAWNER) { if (this.addon.getBlockConfig().isNotHiddenBlock(Material.SPAWNER)) { Map spawnerCountMap = new EnumMap<>(EntityType.class); + spawnerCountMap = this.levelsData.getMdCount().entrySet().stream() .filter(en -> en.getKey() instanceof EntityType) .collect(Collectors.toMap(en -> (EntityType) en.getKey(), Map.Entry::getValue)); - + spawnerCountMap.putAll( + this.levelsData.getUwCount().entrySet().stream().filter(en -> en.getKey() instanceof EntityType) + .collect(Collectors.toMap(en -> (EntityType) en.getKey(), Map.Entry::getValue))); spawnerCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey())).forEachOrdered(entry -> { if (entry.getValue() > 0) { this.blockCountList.add(new BlockRec(entry.getKey(), entry.getValue(), 0)); @@ -633,85 +637,100 @@ private PanelItem createBlockButton(ItemTemplateRecord template, TemplatedPanel. return this.createMaterialButton(template, this.blockCountList.get(index)); } - /** - * This method creates button for block. - * - * @param template the template of the button - * @param blockCount count - * @return PanelItem button - */ private PanelItem createMaterialButton(ItemTemplateRecord template, BlockRec blockCount) { PanelItemBuilder builder = new PanelItemBuilder(); + // Set icon and amount based on the template and block count. if (template.icon() != null) { builder.icon(template.icon().clone()); } - // Show amount if less than 64. if (blockCount.value() < 64) { builder.amount(blockCount.value()); } - final String reference = "level.gui.buttons.material."; - Object key = blockCount.key(); - String description = Utils.prettifyDescription(key, this.user); - String blockId = ""; - int blockValue = 0; - int blockLimit = 0; - String value = ""; - String limit = ""; - String displayMaterial = Utils.prettifyObject(key, this.user); + final String ref = "level.gui.buttons.material."; + BlockDataRec d = getBlockData(blockCount.key()); - if (key instanceof Material m) { - // Material-specific settings. - builder.icon(PanelUtils.getMaterialItem(m)); - blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", m.name()); - blockValue = this.addon.getBlockConfig().getBlockValues().getOrDefault(m, 0); - blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(m), 0); - } else if (key instanceof EntityType e) { - // EntityType-specific settings. - builder.icon(PanelUtils.getEntityEgg(e)); - description += this.user.getTranslation(this.world, "level.gui.buttons.spawner.block-name"); // Put spawner on the end - blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", e.name().concat(SPAWNER)); - blockValue = this.addon.getBlockConfig().getSpawnerValues().getOrDefault(e, 0); - blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(e), 0); + // Override icon from block data if available. + if (d.icon() != null) { + builder.icon(d.icon()); } + // Set name using the title translation if provided. if (template.title() != null) { builder.name(this.user.getTranslation(this.world, template.title(), TextVariables.NUMBER, - String.valueOf(blockCount.value()), "[material]", displayMaterial)); + String.valueOf(blockCount.value()), "[material]", d.displayMaterial())); } - value = blockValue > 0 - ? this.user.getTranslationOrNothing(reference + "value", TextVariables.NUMBER, - String.valueOf(blockValue)) + // Build and set description if provided. + if (template.description() != null) { + String description = buildDescription(template.description(), blockCount, d, ref); + builder.description(description); + } + + return builder.build(); + } + + private String buildDescription(String descriptionTemplate, BlockRec blockCount, BlockDataRec d, String ref) { + String desc = Utils.prettifyDescription(blockCount.key(), this.user) + d.extraDesc(); + String id = this.user.isOp() ? d.blockId() : ""; + String value = d.blockValue() > 0 + ? this.user.getTranslationOrNothing(ref + "value", TextVariables.NUMBER, String.valueOf(d.blockValue())) : ""; - limit = blockLimit > 0 - ? this.user.getTranslationOrNothing(reference + "limit", TextVariables.NUMBER, - String.valueOf(blockLimit)) + + long calculatedRaw = (long) Math.min(d.blockLimit() > 0 ? d.blockLimit() : Integer.MAX_VALUE, + blockCount.value()) * d.blockValue(); + String calculated = calculatedRaw > 0 + ? this.user.getTranslationOrNothing(ref + "calculated", TextVariables.NUMBER, + String.valueOf(calculatedRaw)) + : ""; + + String limit = d.blockLimit() > 0 + ? this.user.getTranslationOrNothing(ref + "limit", TextVariables.NUMBER, String.valueOf(d.blockLimit())) : ""; - String count = this.user.getTranslationOrNothing(reference + "count", TextVariables.NUMBER, + String count = this.user.getTranslationOrNothing(ref + "count", TextVariables.NUMBER, String.valueOf(blockCount.value())); - long calculatedValue = (long) Math.min(blockLimit > 0 ? blockLimit : Integer.MAX_VALUE, - blockCount.value()) * blockValue; - String valueText = calculatedValue > 0 ? this.user.getTranslationOrNothing(reference + "calculated", - TextVariables.NUMBER, String.valueOf(calculatedValue)) : ""; + String translated = this.user.getTranslation(this.world, descriptionTemplate, "[description]", desc, "[id]", id, + "[value]", value, "[calculated]", calculated, "[limit]", limit, "[count]", count); - // Hide block ID unless user is an operator. - if (!user.isOp()) { - blockId = ""; - } - if (template.description() != null) { - builder.description(this.user - .getTranslation(this.world, template.description(), "[description]", description, "[id]", blockId, - "[value]", value, "[calculated]", valueText, "[limit]", limit, "[count]", count) - .replaceAll("(?m)^[ \\t]*\\r?\\n", "").replaceAll("(? opt = ItemsAdderHook.getItemStack(s); + ItemStack icon = opt.orElse(new ItemStack(Material.PAPER)); + String disp = opt.filter(is -> is.getItemMeta().hasDisplayName()) + .map(is -> is.getItemMeta().getDisplayName()).orElse(Utils.prettifyObject(key, this.user)); + return new BlockDataRec(icon, this.user.getTranslationOrNothing(ref + "id", "[id]", s), + this.addon.getBlockConfig().getBlockValues().getOrDefault(s, 0), + Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(s), 0), disp, ""); + } + return new BlockDataRec(null, "", 0, 0, Utils.prettifyObject(key, this.user), ""); } + // --------------------------------------------------------------------- // Section: Other Methods // --------------------------------------------------------------------- diff --git a/src/main/java/world/bentobox/level/panels/ValuePanel.java b/src/main/java/world/bentobox/level/panels/ValuePanel.java index 421f919..172c8b0 100644 --- a/src/main/java/world/bentobox/level/panels/ValuePanel.java +++ b/src/main/java/world/bentobox/level/panels/ValuePanel.java @@ -3,22 +3,22 @@ import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.Locale; import java.util.Objects; import java.util.function.Consumer; import java.util.stream.Collectors; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.World; -import org.bukkit.entity.EntityType; import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import com.google.common.base.Enums; -import lv.id.bonne.panelutils.PanelUtils; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.TemplatedPanel; @@ -26,6 +26,8 @@ import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder; import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord; import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.hooks.ItemsAdderHook; +import world.bentobox.bentobox.util.Util; import world.bentobox.level.Level; import world.bentobox.level.util.ConversationUtils; import world.bentobox.level.util.Utils; @@ -62,7 +64,7 @@ private enum Filter { VALUE_DESC, } - private record BlockRecord(Object keyl, Integer value, Integer limit) { + private record BlockRecord(String keyl, Integer value, Integer limit) { } // --------------------------------------------------------------------- @@ -71,8 +73,6 @@ private record BlockRecord(Object keyl, Integer value, Integer limit) { private static final String BLOCK = "BLOCK"; - private static final String SPAWNER = "_SPAWNER"; - // --------------------------------------------------------------------- // Section: Variables // --------------------------------------------------------------------- @@ -95,7 +95,7 @@ private record BlockRecord(Object keyl, Integer value, Integer limit) { /** * This variable stores the list of elements to display. */ - private final List blockRecordList; + private final List blockRecordList = new ArrayList<>(); /** * This variable stores the list of elements to display. @@ -134,32 +134,12 @@ private ValuePanel(Level addon, this.activeFilter = Filter.NAME_ASC; - this.blockRecordList = Arrays.stream(Material.values()). - filter(Material::isBlock). - filter(Material::isItem). // Remove things like PITCHER_CROP - filter(m -> !m.name().startsWith("LEGACY_")). - filter(this.addon.getBlockConfig()::isNotHiddenBlock). - map(material -> - { - Integer value = this.addon.getBlockConfig().getValue(this.world, material); - Integer limit = this.addon.getBlockConfig().getLimit(material); - - return new BlockRecord(material, - value != null ? value : 0, - limit != null ? limit : 0); - }). - collect(Collectors.toList()); - // Add spawn eggs - this.blockRecordList.addAll(Arrays.stream(EntityType.values()).filter(EntityType::isSpawnable) - .filter(EntityType::isAlive) - .filter(this.addon.getBlockConfig()::isNotHiddenBlock).map(et -> { - Integer value = this.addon.getBlockConfig().getValue(this.world, et); - Integer limit = this.addon.getBlockConfig().getLimit(et); - - return new BlockRecord(et, value != null ? value : 0, limit != null ? limit : 0); - }).collect(Collectors.toList())); - - this.elementList = new ArrayList<>(Material.values().length); + addon.getBlockConfig().getBlockValues().entrySet().stream().filter(en -> this.getIcon(en.getKey()) != null) + .forEach(en -> blockRecordList + .add(new BlockRecord(en.getKey(), Objects.requireNonNullElse(en.getValue(), 0), + Objects.requireNonNullElse(addon.getBlockConfig().getLimit(en.getKey()), 0)))); + + this.elementList = new ArrayList<>(); this.searchText = ""; this.updateFilters(); @@ -264,9 +244,8 @@ private void updateFilters() this.blockRecordList.forEach(rec -> { - if (rec.keyl.toString().toLowerCase().contains(text) - || - Utils.prettifyObject(rec.keyl(), this.user).toLowerCase().contains(text)) + if (rec.keyl.toLowerCase(Locale.ENGLISH).contains(text) + || Utils.prettifyObject(rec.keyl(), this.user).toLowerCase().contains(text)) { this.elementList.add(rec); } @@ -684,164 +663,78 @@ private PanelItem createMaterialButton(ItemTemplateRecord template, TemplatedPan return this.createMaterialButton(template, this.elementList.get(index)); } + private Material getIcon(String key) { + Material icon = Registry.MATERIAL.get(NamespacedKey.fromString(key)); + if (icon == null && key.endsWith("_spawner")) { + icon = Registry.MATERIAL.get(NamespacedKey.fromString(key.substring(0, key.length() - 2) + "_egg")); + } + if (icon == null && addon.isItemsAdder() && ItemsAdderHook.isInRegistry(key)) { + icon = ItemsAdderHook.getItemStack(key).map(ItemStack::getType).orElse(null); + } + if (icon != null && icon.isItem()) { + return icon; + } + return null; + } + /** - * This method creates button for block. + * Creates a material button based on the provided template and block record. * - * @param template the template of the button - * @param blockCount count - * @return PanelItem button + * @param template The button template. + * @param blockCount The block record containing count details. + * @return The created PanelItem button. */ private PanelItem createMaterialButton(ItemTemplateRecord template, BlockRecord blockCount) { PanelItemBuilder builder = new PanelItemBuilder(); + final String baseKey = "level.gui.buttons.material."; - if (template.icon() != null) { - builder.icon(template.icon().clone()); - } - // Show amount if less than 64. - if (blockCount.value() < 64) { - builder.amount(blockCount.value()); - } + // Extract values from blockCount + String key = blockCount.keyl(); + int blockValue = blockCount.value(); + int blockLimit = blockCount.limit(); + double underwaterMultiplier = this.addon.getSettings().getUnderWaterMultiplier(); - final String reference = "level.gui.buttons.material."; - Object key = blockCount.keyl(); + // Build translation strings + String blockId = user.isOp() ? this.user.getTranslationOrNothing(baseKey + "id", "[id]", key) : ""; String description = Utils.prettifyDescription(key, this.user); - String blockId = ""; - int blockValue = 0; - int blockLimit = 0; - String value = ""; - String limit = ""; - String displayMaterial = Utils.prettifyObject(key, this.user); - - if (key instanceof Material m) { - // Material-specific settings. - builder.icon(PanelUtils.getMaterialItem(m)); - blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", m.name()); - blockValue = this.addon.getBlockConfig().getBlockValues().getOrDefault(m, 0); - blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(m), 0); - } else if (key instanceof EntityType e) { - // EntityType-specific settings. - builder.icon(PanelUtils.getEntityEgg(e)); - description += this.user.getTranslation(this.world, "level.gui.buttons.spawner.block-name"); // Put spawner on the end - blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", e.name().concat(SPAWNER)); - blockValue = this.addon.getBlockConfig().getSpawnerValues().getOrDefault(e, 0); - blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(e), 0); + String valueTranslation = this.user.getTranslationOrNothing(baseKey + "value", TextVariables.NUMBER, + String.valueOf(blockValue)); + String limitTranslation = blockLimit > 0 + ? this.user.getTranslationOrNothing(baseKey + "limit", TextVariables.NUMBER, String.valueOf(blockLimit)) + : ""; + + // Determine icon and display material text + Material icon = getIcon(key); + builder.icon((icon == null || icon == Material.AIR) ? Material.PAPER : icon); + + String displayMaterial = (icon == null) ? Util.prettifyText(key) : Utils.prettifyObject(icon, user); + // Special handling for spawn eggs + if (icon != null && icon.name().endsWith("_SPAWN_EGG")) { + displayMaterial = Util.prettifyText(key); } + // Set button title if available if (template.title() != null) { builder.name(this.user.getTranslation(this.world, template.title(), TextVariables.NUMBER, - String.valueOf(blockCount.value()), "[material]", displayMaterial)); + String.valueOf(blockValue), "[material]", displayMaterial)); } - value = blockValue > 0 - ? this.user.getTranslationOrNothing(reference + "value", TextVariables.NUMBER, - String.valueOf(blockValue)) - : ""; - limit = blockLimit > 0 - ? this.user.getTranslationOrNothing(reference + "limit", TextVariables.NUMBER, - String.valueOf(blockLimit)) - : ""; - - // Hide block ID unless user is an operator. - if (!user.isOp()) { - blockId = ""; - } - String underWater; + // Calculate underwater value if applicable + String underWater = underwaterMultiplier != 1.0 ? this.user.getTranslationOrNothing(baseKey + "underwater", + TextVariables.NUMBER, String.valueOf(blockValue * underwaterMultiplier)) : ""; - if (this.addon.getSettings().getUnderWaterMultiplier() > 1.0) { - underWater = this.user.getTranslationOrNothing(reference + "underwater", TextVariables.NUMBER, - String.valueOf(blockCount.value() * this.addon.getSettings().getUnderWaterMultiplier())); - } else { - underWater = ""; - } + // Set button description if provided if (template.description() != null) { - builder.description(this.user + String translatedDescription = this.user .getTranslation(this.world, template.description(), "[description]", description, "[id]", blockId, - "[value]", value, "[underwater]", underWater, "[limit]", limit) - .replaceAll("(?m)^[ \\t]*\\r?\\n", "").replaceAll("(? 0) - { - builder.amount(materialRecord.value()); - } - - if (template.title() != null) - { - builder.name(this.user.getTranslation(this.world, template.title(), - "[material]", Utils.prettifyObject(materialRecord.material(), this.user))); - } - - String description = Utils.prettifyDescription(materialRecord.material(), this.user); - - final String reference = "level.gui.buttons.material."; - String blockId = this.user.getTranslationOrNothing(reference + "id", - "[id]", materialRecord.material().name()); - - String value = this.user.getTranslationOrNothing(reference + "value", - TextVariables.NUMBER, String.valueOf(materialRecord.value())); - - String underWater; - - if (this.addon.getSettings().getUnderWaterMultiplier() > 1.0) - { - underWater = this.user.getTranslationOrNothing(reference + "underwater", - TextVariables.NUMBER, String.valueOf(materialRecord.value() * this.addon.getSettings().getUnderWaterMultiplier())); - } - else - { - underWater = ""; - } - - String limit = materialRecord.limit() > 0 ? this.user.getTranslationOrNothing(reference + "limit", - TextVariables.NUMBER, String.valueOf(materialRecord.limit())) : ""; - - if (template.description() != null) - { - builder.description(this.user.getTranslation(this.world, template.description(), - "[description]", description, - "[id]", blockId, - "[value]", value, - "[underwater]", underWater, - "[limit]", limit). - replaceAll("(?m)^[ \\t]*\\r?\\n", ""). - replaceAll("(? { - addon.log("Material: " + materialRecord.material()); - return true; - }); - - return builder.build(); - }*/ - - // --------------------------------------------------------------------- // Section: Other Methods // --------------------------------------------------------------------- diff --git a/src/main/java/world/bentobox/level/util/Utils.java b/src/main/java/world/bentobox/level/util/Utils.java index 267d865..304271a 100644 --- a/src/main/java/world/bentobox/level/util/Utils.java +++ b/src/main/java/world/bentobox/level/util/Utils.java @@ -143,16 +143,23 @@ public static T getPreviousValue(T[] values, T currentValue) */ public static final String ENTITIES = "level.entities."; private static final String LEVEL_MATERIALS = "level.materials."; + private static final String DESCRIPTION = ".description"; public static String prettifyObject(Object object, User user) { - if (object == null || !(object instanceof Enum)) { + if (object == null) { return ""; } // All supported objects are enums so we can use name() safely. - String key = ((Enum) object).name().toLowerCase(); String translation = ""; - if (object instanceof Material) { + if (object instanceof Material || object instanceof String) { + String key = ""; + if (object instanceof Material) { + key = ((Enum) object).name().toLowerCase(); + } else { + key = (String) object; + } + // Try our translations for Material. translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + ".name"); if (!translation.isEmpty()) @@ -166,9 +173,14 @@ public static String prettifyObject(Object object, User user) { if (!translation.isEmpty()) return translation; - // Fallback to our hook for Material. - return LangUtilsHook.getMaterialName((Material) object, user); + if (object instanceof Material) { + // Fallback to our hook for Material. + return LangUtilsHook.getMaterialName((Material) object, user); + } else { + return key; + } } else if (object instanceof EntityType) { + String key = ((Enum) object).name().toLowerCase(); // Try our translations for EntityType. translation = user.getTranslationOrNothing(ENTITIES + key + ".name"); if (!translation.isEmpty()) @@ -191,16 +203,20 @@ public static String prettifyObject(Object object, User user) { } public static String prettifyDescription(Object object, User user) { + if (object instanceof String key) { + String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + DESCRIPTION); + return translation != null ? translation : ""; + } if (object == null || !(object instanceof Enum)) { return ""; } String key = ((Enum) object).name().toLowerCase(); if (object instanceof Material) { - String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + ".description"); + String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + DESCRIPTION); return translation != null ? translation : ""; } else if (object instanceof EntityType) { - String translation = user.getTranslationOrNothing(ENTITIES + key + ".description"); + String translation = user.getTranslationOrNothing(ENTITIES + key + DESCRIPTION); return translation != null ? translation : ""; } diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml index 72d35e6..c8b35ec 100755 --- a/src/main/resources/addon.yml +++ b/src/main/resources/addon.yml @@ -2,7 +2,7 @@ name: Level main: world.bentobox.level.Level version: ${version}${build.number} icon: DIAMOND -api-version: 2.7.1 +api-version: 3.3.0 authors: tastybento diff --git a/src/main/resources/blockconfig.yml b/src/main/resources/blockconfig.yml index d85cdcf..c03d2da 100644 --- a/src/main/resources/blockconfig.yml +++ b/src/main/resources/blockconfig.yml @@ -1,840 +1,1258 @@ # Block Config file for Level add-on Version ${version} -# +# # This file lists the values for various blocks that are used to calculate the -# island level. -# -# This section lists the limits for any particular block. Blocks over this amount +# island level. Block names are in lower case. +# +# ItemsAdder blocks can be listed using their full namespaced ID like: +# iasurvival:modern_stone: 100 +# The key for a block can be found by looking at it in-game and using /iablock +# +# The limits section lists the maximum number for any particular block. Blocks over this amount # are not counted. -# Format: -# MATERIAL: limit limits: - COBBLESTONE: 10000 - NETHERRACK: 1000 + cobblestone: 10000 + netherrack: 1000 # These blocks will never be shown in the GUI even if they have value hidden-blocks: - - BEDROCK - - AIR +- bedrock +- air blocks: - ACACIA_BUTTON: 1 - ACACIA_DOOR: 2 - ACACIA_FENCE: 2 - ACACIA_FENCE_GATE: 4 - ACACIA_LEAVES: 0 - ACACIA_LOG: 0 - ACACIA_PLANKS: 1 - ACACIA_PRESSURE_PLATE: 2 - ACACIA_SAPLING: 1 - ACACIA_SIGN: 6 - ACACIA_SLAB: 1 - ACACIA_STAIRS: 2 - ACACIA_TRAPDOOR: 3 - ACACIA_WALL_SIGN: 6 - ACACIA_WOOD: 1 - ACTIVATOR_RAIL: 1 - AIR: 0 - ALLIUM: 1 - ANCIENT_DEBRIS: 10 - ANDESITE: 1 - ANDESITE_SLAB: 1 - ANDESITE_STAIRS: 1 - ANDESITE_WALL: 1 - ANVIL: 10 - ATTACHED_MELON_STEM: 1 - ATTACHED_PUMPKIN_STEM: 1 - AZURE_BLUET: 1 - BAMBOO: 1 - BAMBOO_SAPLING: 1 - BARREL: 2 - BARRIER: 0 - BASALT: 1 - BEACON: 300 - BEDROCK: 0 - BEETROOTS: 1 - BELL: 100 - BIRCH_BUTTON: 1 - BIRCH_DOOR: 2 - BIRCH_FENCE: 2 - BIRCH_FENCE_GATE: 4 - BIRCH_LEAVES: 0 - BIRCH_LOG: 0 - BIRCH_PLANKS: 1 - BIRCH_PRESSURE_PLATE: 2 - BIRCH_SAPLING: 1 - BIRCH_SIGN: 6 - BIRCH_SLAB: 1 - BIRCH_STAIRS: 2 - BIRCH_TRAPDOOR: 3 - BIRCH_WALL_SIGN: 6 - BIRCH_WOOD: 1 - BLACK_BANNER: 2 - BLACK_BED: 6 - BLACK_CARPET: 1 - BLACK_CONCRETE: 3 - BLACK_CONCRETE_POWDER: 2 - BLACK_GLAZED_TERRACOTTA: 5 - BLACK_SHULKER_BOX: 11 - BLACK_STAINED_GLASS: 2 - BLACK_STAINED_GLASS_PANE: 1 - BLACK_TERRACOTTA: 2 - BLACK_WALL_BANNER: 2 - BLACK_WOOL: 2 - BLACKSTONE: 1 - BLACKSTONE_SLAB: 1 - BLACKSTONE_STAIRS: 2 - BLACKSTONE_WALL: 1 - BLAST_FURNACE: 150 - BLUE_BANNER: 2 - BLUE_BED: 6 - BLUE_CARPET: 1 - BLUE_CONCRETE: 3 - BLUE_CONCRETE_POWDER: 2 - BLUE_GLAZED_TERRACOTTA: 5 - BLUE_ICE: 1 - BLUE_ORCHID: 1 - BLUE_SHULKER_BOX: 11 - BLUE_STAINED_GLASS: 2 - BLUE_STAINED_GLASS_PANE: 1 - BLUE_TERRACOTTA: 2 - BLUE_WALL_BANNER: 2 - BLUE_WOOL: 2 - BONE_BLOCK: 1 - BOOKSHELF: 5 - BRAIN_CORAL: 1 - BRAIN_CORAL_BLOCK: 1 - BRAIN_CORAL_FAN: 1 - BRAIN_CORAL_WALL_FAN: 1 - BREWING_STAND: 20 - BRICK_SLAB: 3 - BRICK_STAIRS: 5 - BRICK_WALL: 5 - BRICKS: 5 - BROWN_BANNER: 2 - BROWN_BED: 6 - BROWN_CARPET: 1 - BROWN_CONCRETE: 3 - BROWN_CONCRETE_POWDER: 2 - BROWN_GLAZED_TERRACOTTA: 5 - BROWN_MUSHROOM: 1 - BROWN_MUSHROOM_BLOCK: 1 - BROWN_SHULKER_BOX: 11 - BROWN_STAINED_GLASS: 2 - BROWN_STAINED_GLASS_PANE: 1 - BROWN_TERRACOTTA: 2 - BROWN_WALL_BANNER: 2 - BROWN_WOOL: 2 - BUBBLE_COLUMN: 1 - BUBBLE_CORAL: 1 - BUBBLE_CORAL_BLOCK: 1 - BUBBLE_CORAL_FAN: 1 - BUBBLE_CORAL_WALL_FAN: 1 - CACTUS: 1 - CAKE: 9 - CAMPFIRE: 5 - CARROTS: 1 - CARTOGRAPHY_TABLE: 6 - CARVED_PUMPKIN: 2 - CAULDRON: 10 - CAVE_AIR: 0 - CHAIN: 2 - CHAIN_COMMAND_BLOCK: 0 - CHEST: 8 - CHIPPED_ANVIL: 9 - CHISELED_NETHER_BRICKS: 2 - CHISELED_POLISHED_BLACKSTONE: 2 - CHISELED_QUARTZ_BLOCK: 2 - CHISELED_RED_SANDSTONE: 2 - CHISELED_SANDSTONE: 2 - CHISELED_STONE_BRICKS: 2 - CHORUS_FLOWER: 1 - CHORUS_PLANT: 1 - CLAY: 2 - COAL_BLOCK: 9 - COAL_ORE: 1 - COARSE_DIRT: 2 - COBBLESTONE: 1 - COBBLESTONE_SLAB: 1 - COBBLESTONE_STAIRS: 2 - COBBLESTONE_WALL: 1 - COBWEB: 10 - COCOA: 1 - COMMAND_BLOCK: 0 - COMPARATOR: 10 - COMPOSTER: 9 - CONDUIT: 1 - CORNFLOWER: 1 - CRACKED_NETHER_BRICKS: 1 - CRACKED_POLISHED_BLACKSTONE_BRICKS: 1 - CRACKED_STONE_BRICKS: 2 - CRAFTING_TABLE: 1 - CREEPER_HEAD: 1 - CREEPER_WALL_HEAD: 1 - CRIMSON_BUTTON: 1 - CRIMSON_DOOR: 2 - CRIMSON_FENCE: 2 - CRIMSON_FENCE_GATE: 4 - CRIMSON_FUNGUS: 1 - CRIMSON_HYPHAE: 1 - CRIMSON_NYLIUM: 1 - CRIMSON_PLANKS: 1 - CRIMSON_PRESSURE_PLATE: 2 - CRIMSON_ROOTS: 1 - CRIMSON_SIGN: 6 - CRIMSON_SLAB: 1 - CRIMSON_STAIRS: 2 - CRIMSON_STEM: 1 - CRIMSON_TRAPDOOR: 3 - CRIMSON_WALL_SIGN: 6 - CRYING_OBSIDIAN: 15 - CUT_RED_SANDSTONE: 1 - CUT_RED_SANDSTONE_SLAB: 1 - CUT_SANDSTONE: 1 - CUT_SANDSTONE_SLAB: 1 - CYAN_BANNER: 2 - CYAN_BED: 6 - CYAN_CARPET: 1 - CYAN_CONCRETE: 3 - CYAN_CONCRETE_POWDER: 2 - CYAN_GLAZED_TERRACOTTA: 5 - CYAN_SHULKER_BOX: 11 - CYAN_STAINED_GLASS: 2 - CYAN_STAINED_GLASS_PANE: 1 - CYAN_TERRACOTTA: 2 - CYAN_WALL_BANNER: 2 - CYAN_WOOL: 2 - DAMAGED_ANVIL: 5 - DANDELION: 1 - DARK_OAK_BUTTON: 1 - DARK_OAK_DOOR: 2 - DARK_OAK_FENCE: 2 - DARK_OAK_FENCE_GATE: 4 - DARK_OAK_LEAVES: 0 - DARK_OAK_LOG: 0 - DARK_OAK_PLANKS: 1 - DARK_OAK_PRESSURE_PLATE: 2 - DARK_OAK_SAPLING: 1 - DARK_OAK_SIGN: 6 - DARK_OAK_SLAB: 1 - DARK_OAK_STAIRS: 2 - DARK_OAK_TRAPDOOR: 3 - DARK_OAK_WALL_SIGN: 6 - DARK_OAK_WOOD: 1 - DARK_PRISMARINE: 1 - DARK_PRISMARINE_SLAB: 1 - DARK_PRISMARINE_STAIRS: 2 - DAYLIGHT_DETECTOR: 10 - DEAD_BRAIN_CORAL: 1 - DEAD_BRAIN_CORAL_BLOCK: 1 - DEAD_BRAIN_CORAL_FAN: 1 - DEAD_BRAIN_CORAL_WALL_FAN: 1 - DEAD_BUBBLE_CORAL: 1 - DEAD_BUBBLE_CORAL_BLOCK: 1 - DEAD_BUBBLE_CORAL_FAN: 1 - DEAD_BUBBLE_CORAL_WALL_FAN: 1 - DEAD_BUSH: 1 - DEAD_FIRE_CORAL: 1 - DEAD_FIRE_CORAL_BLOCK: 1 - DEAD_FIRE_CORAL_FAN: 1 - DEAD_FIRE_CORAL_WALL_FAN: 1 - DEAD_HORN_CORAL: 1 - DEAD_HORN_CORAL_BLOCK: 1 - DEAD_HORN_CORAL_FAN: 1 - DEAD_HORN_CORAL_WALL_FAN: 1 - DEAD_TUBE_CORAL: 1 - DEAD_TUBE_CORAL_BLOCK: 1 - DEAD_TUBE_CORAL_FAN: 1 - DEAD_TUBE_CORAL_WALL_FAN: 1 - DETECTOR_RAIL: 10 - DIAMOND_BLOCK: 300 - DIAMOND_ORE: 1 - DIORITE: 1 - DIORITE_SLAB: 1 - DIORITE_STAIRS: 1 - DIORITE_WALL: 1 - DIRT: 3 - DIRT_PATH: 4 - DISPENSER: 5 - DRAGON_EGG: 150 - DRAGON_HEAD: 1 - DRAGON_WALL_HEAD: 1 - DRIED_KELP_BLOCK: 1 - DROPPER: 5 - EMERALD_BLOCK: 150 - EMERALD_ORE: 1 - ENCHANTING_TABLE: 150 - END_GATEWAY: 0 - END_PORTAL: 0 - END_PORTAL_FRAME: 0 - END_ROD: 1 - END_STONE: 1 - END_STONE_BRICK_SLAB: 2 - END_STONE_BRICK_STAIRS: 2 - END_STONE_BRICK_WALL: 2 - END_STONE_BRICKS: 2 - ENDER_CHEST: 150 - FARMLAND: 1 - FERN: 1 - FIRE: 0 - FIRE_CORAL: 1 - FIRE_CORAL_BLOCK: 1 - FIRE_CORAL_FAN: 1 - FIRE_CORAL_WALL_FAN: 1 - FLETCHING_TABLE: 8 - FLOWER_POT: 1 - FROSTED_ICE: 1 - FURNACE: 8 - GILDED_BLACKSTONE: 1 - GLASS: 2 - GLASS_PANE: 1 - GLOWSTONE: 1 - GOLD_BLOCK: 150 - GOLD_ORE: 1 - GRANITE: 1 - GRANITE_SLAB: 1 - GRANITE_STAIRS: 1 - GRANITE_WALL: 1 - SHORT_GRASS: 4 - GRASS_BLOCK: 4 - GRAVEL: 1 - GRAY_BANNER: 2 - GRAY_BED: 6 - GRAY_CARPET: 1 - GRAY_CONCRETE: 3 - GRAY_CONCRETE_POWDER: 2 - GRAY_GLAZED_TERRACOTTA: 5 - GRAY_SHULKER_BOX: 11 - GRAY_STAINED_GLASS: 2 - GRAY_STAINED_GLASS_PANE: 1 - GRAY_TERRACOTTA: 2 - GRAY_WALL_BANNER: 2 - GRAY_WOOL: 2 - GREEN_BANNER: 2 - GREEN_BED: 6 - GREEN_CARPET: 1 - GREEN_CONCRETE: 3 - GREEN_CONCRETE_POWDER: 2 - GREEN_GLAZED_TERRACOTTA: 5 - GREEN_SHULKER_BOX: 11 - GREEN_STAINED_GLASS: 2 - GREEN_STAINED_GLASS_PANE: 1 - GREEN_TERRACOTTA: 2 - GREEN_WALL_BANNER: 2 - GREEN_WOOL: 2 - GRINDSTONE: 8 - HAY_BLOCK: 2 - HEAVY_WEIGHTED_PRESSURE_PLATE: 2 - HONEY_BLOCK: 1 - HONEYCOMB_BLOCK: 1 - HOPPER: -10 - HORN_CORAL: 1 - HORN_CORAL_BLOCK: 1 - HORN_CORAL_FAN: 1 - HORN_CORAL_WALL_FAN: 1 - ICE: 5 - INFESTED_CHISELED_STONE_BRICKS: 2 - INFESTED_COBBLESTONE: 1 - INFESTED_CRACKED_STONE_BRICKS: 2 - INFESTED_MOSSY_STONE_BRICKS: 2 - INFESTED_STONE: 1 - INFESTED_STONE_BRICKS: 2 - IRON_BARS: 2 - IRON_BLOCK: 10 - IRON_DOOR: 5 - IRON_ORE: 1 - IRON_TRAPDOOR: 4 - JACK_O_LANTERN: 2 - JIGSAW: 1 - JUKEBOX: 10 - JUNGLE_BUTTON: 1 - JUNGLE_DOOR: 2 - JUNGLE_FENCE: 2 - JUNGLE_FENCE_GATE: 4 - JUNGLE_LEAVES: 0 - JUNGLE_LOG: 0 - JUNGLE_PLANKS: 1 - JUNGLE_PRESSURE_PLATE: 2 - JUNGLE_SAPLING: 1 - JUNGLE_SIGN: 6 - JUNGLE_SLAB: 1 - JUNGLE_STAIRS: 2 - JUNGLE_TRAPDOOR: 3 - JUNGLE_WALL_SIGN: 6 - JUNGLE_WOOD: 1 - KELP: 1 - KELP_PLANT: 1 - LADDER: 2 - LANTERN: 3 - LAPIS_BLOCK: 10 - LAPIS_ORE: 1 - LARGE_FERN: 1 - LAVA: 0 - LECTERN: 8 - LEVER: 1 - LIGHT_BLUE_BANNER: 2 - LIGHT_BLUE_BED: 6 - LIGHT_BLUE_CARPET: 1 - LIGHT_BLUE_CONCRETE: 3 - LIGHT_BLUE_CONCRETE_POWDER: 2 - LIGHT_BLUE_GLAZED_TERRACOTTA: 5 - LIGHT_BLUE_SHULKER_BOX: 11 - LIGHT_BLUE_STAINED_GLASS: 2 - LIGHT_BLUE_STAINED_GLASS_PANE: 1 - LIGHT_BLUE_TERRACOTTA: 2 - LIGHT_BLUE_WALL_BANNER: 2 - LIGHT_BLUE_WOOL: 2 - LIGHT_GRAY_BANNER: 2 - LIGHT_GRAY_BED: 6 - LIGHT_GRAY_CARPET: 1 - LIGHT_GRAY_CONCRETE: 3 - LIGHT_GRAY_CONCRETE_POWDER: 2 - LIGHT_GRAY_GLAZED_TERRACOTTA: 5 - LIGHT_GRAY_SHULKER_BOX: 11 - LIGHT_GRAY_STAINED_GLASS: 2 - LIGHT_GRAY_STAINED_GLASS_PANE: 1 - LIGHT_GRAY_TERRACOTTA: 2 - LIGHT_GRAY_WALL_BANNER: 2 - LIGHT_GRAY_WOOL: 2 - LIGHT_WEIGHTED_PRESSURE_PLATE: 3 - LILAC: 1 - LILY_OF_THE_VALLEY: 1 - LILY_PAD: 5 - LIME_BANNER: 2 - LIME_BED: 6 - LIME_CARPET: 1 - LIME_CONCRETE: 3 - LIME_CONCRETE_POWDER: 2 - LIME_GLAZED_TERRACOTTA: 5 - LIME_SHULKER_BOX: 11 - LIME_STAINED_GLASS: 2 - LIME_STAINED_GLASS_PANE: 1 - LIME_TERRACOTTA: 2 - LIME_WALL_BANNER: 2 - LIME_WOOL: 2 - LODESTONE: 10 - LOOM: 5 - MAGENTA_BANNER: 2 - MAGENTA_BED: 6 - MAGENTA_CARPET: 1 - MAGENTA_CONCRETE: 3 - MAGENTA_CONCRETE_POWDER: 2 - MAGENTA_GLAZED_TERRACOTTA: 5 - MAGENTA_SHULKER_BOX: 11 - MAGENTA_STAINED_GLASS: 2 - MAGENTA_STAINED_GLASS_PANE: 1 - MAGENTA_TERRACOTTA: 2 - MAGENTA_WALL_BANNER: 2 - MAGENTA_WOOL: 2 - MAGMA_BLOCK: 1 - MELON: 1 - MELON_STEM: 1 - MOSSY_COBBLESTONE: 1 - MOSSY_COBBLESTONE_SLAB: 1 - MOSSY_COBBLESTONE_STAIRS: 1 - MOSSY_COBBLESTONE_WALL: 1 - MOSSY_STONE_BRICK_SLAB: 2 - MOSSY_STONE_BRICK_STAIRS: 2 - MOSSY_STONE_BRICK_WALL: 2 - MOSSY_STONE_BRICKS: 2 - MOVING_PISTON: 1 - MUSHROOM_STEM: 1 - MYCELIUM: 5 - NETHER_BRICK_FENCE: 2 - NETHER_BRICK_SLAB: 1 - NETHER_BRICK_STAIRS: 2 - NETHER_BRICK_WALL: 2 - NETHER_BRICKS: 2 - NETHER_GOLD_ORE: 1 - NETHER_PORTAL: 1 - NETHER_QUARTZ_ORE: 1 - NETHER_SPROUTS: 1 - NETHER_WART: 1 - NETHER_WART_BLOCK: 2 - NETHERITE_BLOCK: 1 - NETHERRACK: 1 - NOTE_BLOCK: 10 - OAK_BUTTON: 1 - OAK_DOOR: 2 - OAK_FENCE: 2 - OAK_FENCE_GATE: 4 - OAK_LEAVES: 0 - OAK_LOG: 0 - OAK_PLANKS: 1 - OAK_PRESSURE_PLATE: 2 - OAK_SAPLING: 1 - OAK_SIGN: 6 - OAK_SLAB: 1 - OAK_STAIRS: 2 - OAK_TRAPDOOR: 3 - OAK_WALL_SIGN: 6 - OAK_WOOD: 1 - OBSERVER: 1 - OBSIDIAN: 10 - ORANGE_BANNER: 2 - ORANGE_BED: 6 - ORANGE_CARPET: 1 - ORANGE_CONCRETE: 3 - ORANGE_CONCRETE_POWDER: 2 - ORANGE_GLAZED_TERRACOTTA: 5 - ORANGE_SHULKER_BOX: 11 - ORANGE_STAINED_GLASS: 2 - ORANGE_STAINED_GLASS_PANE: 1 - ORANGE_TERRACOTTA: 2 - ORANGE_TULIP: 1 - ORANGE_WALL_BANNER: 2 - ORANGE_WOOL: 2 - OXEYE_DAISY: 1 - PACKED_ICE: 5 - PEONY: 1 - PETRIFIED_OAK_SLAB: 1 - PINK_BANNER: 2 - PINK_BED: 6 - PINK_CARPET: 1 - PINK_CONCRETE: 3 - PINK_CONCRETE_POWDER: 2 - PINK_GLAZED_TERRACOTTA: 5 - PINK_SHULKER_BOX: 11 - PINK_STAINED_GLASS: 2 - PINK_STAINED_GLASS_PANE: 1 - PINK_TERRACOTTA: 2 - PINK_TULIP: 1 - PINK_WALL_BANNER: 2 - PINK_WOOL: 2 - PISTON: 2 - PISTON_HEAD: 1 - PLAYER_HEAD: 1 - PLAYER_WALL_HEAD: 1 - PODZOL: 2 - POLISHED_ANDESITE: 1 - POLISHED_ANDESITE_SLAB: 1 - POLISHED_ANDESITE_STAIRS: 1 - POLISHED_BASALT: 1 - POLISHED_BLACKSTONE: 1 - POLISHED_BLACKSTONE_BRICK_SLAB: 2 - POLISHED_BLACKSTONE_BRICK_STAIRS: 2 - POLISHED_BLACKSTONE_BRICK_WALL: 2 - POLISHED_BLACKSTONE_BRICKS: 2 - POLISHED_BLACKSTONE_BUTTON: 1 - POLISHED_BLACKSTONE_PRESSURE_PLATE: 2 - POLISHED_BLACKSTONE_SLAB: 1 - POLISHED_BLACKSTONE_STAIRS: 2 - POLISHED_BLACKSTONE_WALL: 1 - POLISHED_DIORITE: 1 - POLISHED_DIORITE_SLAB: 1 - POLISHED_DIORITE_STAIRS: 1 - POLISHED_GRANITE: 1 - POLISHED_GRANITE_SLAB: 1 - POLISHED_GRANITE_STAIRS: 1 - POPPY: 1 - POTATOES: 1 - POTTED_ACACIA_SAPLING: 1 - POTTED_ALLIUM: 1 - POTTED_AZURE_BLUET: 1 - POTTED_BAMBOO: 1 - POTTED_BIRCH_SAPLING: 1 - POTTED_BLUE_ORCHID: 1 - POTTED_BROWN_MUSHROOM: 1 - POTTED_CACTUS: 1 - POTTED_CORNFLOWER: 1 - POTTED_CRIMSON_FUNGUS: 1 - POTTED_CRIMSON_ROOTS: 1 - POTTED_DANDELION: 1 - POTTED_DARK_OAK_SAPLING: 1 - POTTED_DEAD_BUSH: 1 - POTTED_FERN: 1 - POTTED_JUNGLE_SAPLING: 1 - POTTED_LILY_OF_THE_VALLEY: 1 - POTTED_OAK_SAPLING: 1 - POTTED_ORANGE_TULIP: 1 - POTTED_OXEYE_DAISY: 1 - POTTED_PINK_TULIP: 1 - POTTED_POPPY: 1 - POTTED_RED_MUSHROOM: 1 - POTTED_RED_TULIP: 1 - POTTED_SPRUCE_SAPLING: 1 - POTTED_WARPED_FUNGUS: 1 - POTTED_WARPED_ROOTS: 1 - POTTED_WHITE_TULIP: 1 - POTTED_WITHER_ROSE: 1 - POWERED_RAIL: 2 - PRISMARINE: 1 - PRISMARINE_BRICK_SLAB: 1 - PRISMARINE_BRICK_STAIRS: 2 - PRISMARINE_BRICKS: 2 - PRISMARINE_SLAB: 1 - PRISMARINE_STAIRS: 2 - PRISMARINE_WALL: 2 - PUMPKIN: 1 - PUMPKIN_STEM: 1 - PURPLE_BANNER: 2 - PURPLE_BED: 6 - PURPLE_CARPET: 1 - PURPLE_CONCRETE: 3 - PURPLE_CONCRETE_POWDER: 2 - PURPLE_GLAZED_TERRACOTTA: 5 - PURPLE_SHULKER_BOX: 11 - PURPLE_STAINED_GLASS: 2 - PURPLE_STAINED_GLASS_PANE: 1 - PURPLE_TERRACOTTA: 2 - PURPLE_WALL_BANNER: 2 - PURPLE_WOOL: 2 - PURPUR_BLOCK: 1 - PURPUR_PILLAR: 1 - PURPUR_SLAB: 1 - PURPUR_STAIRS: 2 - QUARTZ_BLOCK: 1 - QUARTZ_BRICKS: 2 - QUARTZ_PILLAR: 1 - QUARTZ_SLAB: 1 - QUARTZ_STAIRS: 2 - RAIL: 1 - RED_BANNER: 2 - RED_BED: 6 - RED_CARPET: 1 - RED_CONCRETE: 3 - RED_CONCRETE_POWDER: 2 - RED_GLAZED_TERRACOTTA: 5 - RED_MUSHROOM: 1 - RED_MUSHROOM_BLOCK: 1 - RED_NETHER_BRICK_SLAB: 2 - RED_NETHER_BRICK_STAIRS: 2 - RED_NETHER_BRICK_WALL: 2 - RED_NETHER_BRICKS: 2 - RED_SAND: 1 - RED_SANDSTONE: 1 - RED_SANDSTONE_SLAB: 1 - RED_SANDSTONE_STAIRS: 2 - RED_SANDSTONE_WALL: 2 - RED_SHULKER_BOX: 11 - RED_STAINED_GLASS: 2 - RED_STAINED_GLASS_PANE: 1 - RED_TERRACOTTA: 2 - RED_TULIP: 1 - RED_WALL_BANNER: 2 - RED_WOOL: 2 - REDSTONE_BLOCK: 10 - REDSTONE_LAMP: 10 - REDSTONE_ORE: 1 - REDSTONE_TORCH: 5 - REDSTONE_WALL_TORCH: 5 - REDSTONE_WIRE: 1 - REPEATER: 6 - REPEATING_COMMAND_BLOCK: 0 - RESPAWN_ANCHOR: 100 - ROSE_BUSH: 1 - SAND: 1 - SANDSTONE: 1 - SANDSTONE_SLAB: 1 - SANDSTONE_STAIRS: 2 - SANDSTONE_WALL: 2 - SCAFFOLDING: 1 - SEA_LANTERN: 9 - SEA_PICKLE: 1 - SEAGRASS: 1 - SHROOMLIGHT: 1 - SHULKER_BOX: 10 - SKELETON_SKULL: 10 - SKELETON_WALL_SKULL: 100 - SLIME_BLOCK: 10 - SMITHING_TABLE: 6 - SMOKER: 10 - SMOOTH_QUARTZ: 1 - SMOOTH_QUARTZ_SLAB: 1 - SMOOTH_QUARTZ_STAIRS: 1 - SMOOTH_RED_SANDSTONE: 1 - SMOOTH_RED_SANDSTONE_SLAB: 1 - SMOOTH_RED_SANDSTONE_STAIRS: 1 - SMOOTH_SANDSTONE: 1 - SMOOTH_SANDSTONE_SLAB: 1 - SMOOTH_SANDSTONE_STAIRS: 1 - SMOOTH_STONE: 1 - SMOOTH_STONE_SLAB: 1 - SNOW: 1 - SNOW_BLOCK: 1 - SOUL_CAMPFIRE: 1 - SOUL_FIRE: 1 - SOUL_LANTERN: 1 - SOUL_SAND: 2 - SOUL_SOIL: 1 - SOUL_TORCH: 1 - SOUL_WALL_TORCH: 1 - SPAWNER: 1 - SPONGE: 10 - SPRUCE_BUTTON: 1 - SPRUCE_DOOR: 2 - SPRUCE_FENCE: 2 - SPRUCE_FENCE_GATE: 4 - SPRUCE_LEAVES: 0 - SPRUCE_LOG: 0 - SPRUCE_PLANKS: 1 - SPRUCE_PRESSURE_PLATE: 2 - SPRUCE_SAPLING: 1 - SPRUCE_SIGN: 6 - SPRUCE_SLAB: 1 - SPRUCE_STAIRS: 2 - SPRUCE_TRAPDOOR: 3 - SPRUCE_WALL_SIGN: 6 - SPRUCE_WOOD: 1 - STICKY_PISTON: 1 - STONE: 1 - STONE_BRICK_SLAB: 1 - STONE_BRICK_STAIRS: 2 - STONE_BRICK_WALL: 2 - STONE_BRICKS: 2 - STONE_BUTTON: 1 - STONE_PRESSURE_PLATE: 2 - STONE_SLAB: 1 - STONE_STAIRS: 1 - STONECUTTER: 4 - STRIPPED_ACACIA_LOG: 0 - STRIPPED_ACACIA_WOOD: 1 - STRIPPED_BIRCH_LOG: 0 - STRIPPED_BIRCH_WOOD: 1 - STRIPPED_CRIMSON_HYPHAE: 1 - STRIPPED_CRIMSON_STEM: 1 - STRIPPED_DARK_OAK_LOG: 0 - STRIPPED_DARK_OAK_WOOD: 1 - STRIPPED_JUNGLE_LOG: 0 - STRIPPED_JUNGLE_WOOD: 1 - STRIPPED_OAK_LOG: 0 - STRIPPED_OAK_WOOD: 1 - STRIPPED_SPRUCE_LOG: 0 - STRIPPED_SPRUCE_WOOD: 1 - STRIPPED_WARPED_HYPHAE: 1 - STRIPPED_WARPED_STEM: 1 - STRUCTURE_BLOCK: 0 - STRUCTURE_VOID: 0 - SUGAR_CANE: 1 - SUNFLOWER: 1 - SWEET_BERRY_BUSH: 1 - TALL_GRASS: 1 - TALL_SEAGRASS: 1 - TARGET: 5 - TERRACOTTA: 2 - TNT: 5 - TORCH: 1 - TRAPPED_CHEST: 10 - TRIPWIRE: 2 - TRIPWIRE_HOOK: 2 - TUBE_CORAL: 1 - TUBE_CORAL_BLOCK: 1 - TUBE_CORAL_FAN: 1 - TUBE_CORAL_WALL_FAN: 1 - TURTLE_EGG: 1 - TWISTING_VINES: 1 - TWISTING_VINES_PLANT: 1 - VINE: 1 - VOID_AIR: 0 - WALL_TORCH: 1 - WARPED_BUTTON: 1 - WARPED_DOOR: 3 - WARPED_FENCE: 2 - WARPED_FENCE_GATE: 4 - WARPED_FUNGUS: 1 - WARPED_HYPHAE: 1 - WARPED_NYLIUM: 1 - WARPED_PLANKS: 1 - WARPED_PRESSURE_PLATE: 2 - WARPED_ROOTS: 1 - WARPED_SIGN: 6 - WARPED_SLAB: 1 - WARPED_STAIRS: 2 - WARPED_STEM: 1 - WARPED_TRAPDOOR: 3 - WARPED_WALL_SIGN: 6 - WARPED_WART_BLOCK: 1 - WATER: 0 - WEEPING_VINES: 1 - WEEPING_VINES_PLANT: 1 - WET_SPONGE: 10 - WHEAT: 1 - WHITE_BANNER: 2 - WHITE_BED: 6 - WHITE_CARPET: 1 - WHITE_CONCRETE: 3 - WHITE_CONCRETE_POWDER: 2 - WHITE_GLAZED_TERRACOTTA: 5 - WHITE_SHULKER_BOX: 11 - WHITE_STAINED_GLASS: 2 - WHITE_STAINED_GLASS_PANE: 1 - WHITE_TERRACOTTA: 2 - WHITE_TULIP: 1 - WHITE_WALL_BANNER: 2 - WHITE_WOOL: 2 - WITHER_ROSE: 1 - WITHER_SKELETON_SKULL: 10 - WITHER_SKELETON_WALL_SKULL: 10 - YELLOW_BANNER: 2 - YELLOW_BED: 6 - YELLOW_CARPET: 1 - YELLOW_CONCRETE: 3 - YELLOW_CONCRETE_POWDER: 2 - YELLOW_GLAZED_TERRACOTTA: 5 - YELLOW_SHULKER_BOX: 11 - YELLOW_STAINED_GLASS: 2 - YELLOW_STAINED_GLASS_PANE: 1 - YELLOW_TERRACOTTA: 2 - YELLOW_WALL_BANNER: 2 - YELLOW_WOOL: 2 - ZOMBIE_HEAD: 1 - ZOMBIE_WALL_HEAD: 1 + #iasurvival:modern_stone: 1 + acacia_button: 1 + acacia_door: 2 + acacia_fence: 2 + acacia_fence_gate: 4 + acacia_leaves: 0 + acacia_log: 0 + acacia_planks: 1 + acacia_pressure_plate: 2 + acacia_sapling: 0 + acacia_sign: 6 + acacia_slab: 3 + acacia_stairs: 2 + acacia_trapdoor: 3 + acacia_wall_sign: 6 + acacia_wood: 0 + activator_rail: 7 + air: 0 + allium: 1 + ancient_debris: 10 + andesite: 1 + andesite_slab: 1 + andesite_stairs: 1 + andesite_wall: 1 + anvil: 10 + attached_melon_stem: 0 + attached_pumpkin_stem: 0 + azure_bluet: 1 + bamboo: 0 + bamboo_sapling: 0 + barrel: 2 + barrier: 0 + basalt: 0 + beacon: 300 + bedrock: 0 + beetroots: 0 + bell: 100 + birch_button: 1 + birch_door: 2 + birch_fence: 2 + birch_fence_gate: 4 + birch_leaves: 0 + birch_log: 0 + birch_planks: 1 + birch_pressure_plate: 2 + birch_sapling: 0 + birch_sign: 6 + birch_slab: 1 + birch_stairs: 2 + birch_trapdoor: 3 + birch_wall_sign: 6 + birch_wood: 0 + black_banner: 2 + black_bed: 6 + black_carpet: 1 + black_concrete: 3 + black_concrete_powder: 2 + black_glazed_terracotta: 5 + black_shulker_box: 11 + black_stained_glass: 2 + black_stained_glass_pane: 1 + black_terracotta: 2 + black_wall_banner: 2 + black_wool: 2 + blackstone: 1 + blackstone_slab: 1 + blackstone_stairs: 2 + blackstone_wall: 1 + blast_furnace: 150 + blue_banner: 2 + blue_bed: 6 + blue_carpet: 1 + blue_concrete: 3 + blue_concrete_powder: 2 + blue_glazed_terracotta: 5 + blue_ice: 10 + blue_orchid: 1 + blue_shulker_box: 11 + blue_stained_glass: 2 + blue_stained_glass_pane: 1 + blue_terracotta: 2 + blue_wall_banner: 2 + blue_wool: 2 + bone_block: 1 + bookshelf: 5 + brain_coral: 1 + brain_coral_block: 1 + brain_coral_fan: 1 + brain_coral_wall_fan: 1 + brewing_stand: 20 + brick_slab: 3 + brick_stairs: 5 + brick_wall: 5 + bricks: 5 + brown_banner: 2 + brown_bed: 6 + brown_carpet: 1 + brown_concrete: 3 + brown_concrete_powder: 2 + brown_glazed_terracotta: 5 + brown_mushroom: 1 + brown_mushroom_block: 1 + brown_shulker_box: 11 + brown_stained_glass: 2 + brown_stained_glass_pane: 1 + brown_terracotta: 2 + brown_wall_banner: 2 + brown_wool: 2 + bubble_column: 1 + bubble_coral: 1 + bubble_coral_block: 1 + bubble_coral_fan: 1 + bubble_coral_wall_fan: 1 + cactus: 0 + cake: 9 + campfire: 5 + carrots: 1 + cartography_table: 6 + carved_pumpkin: 2 + cauldron: 10 + cave_air: 0 + chain: 2 + chain_command_block: 0 + chest: 8 + chipped_anvil: 9 + chiseled_nether_bricks: 2 + chiseled_polished_blackstone: 2 + chiseled_quartz_block: 2 + chiseled_red_sandstone: 2 + chiseled_sandstone: 2 + chiseled_stone_bricks: 2 + chorus_flower: 5 + chorus_plant: 5 + clay: 2 + coal_block: 9 + coal_ore: 3 + coarse_dirt: 2 + cobblestone: 0 + cobblestone_slab: 1 + cobblestone_stairs: 2 + cobblestone_wall: 1 + cobweb: 10 + cocoa: 0 + command_block: 0 + comparator: 10 + composter: 9 + conduit: 15 + cornflower: 1 + cracked_stone_bricks: 2 + crafting_table: 4 + creeper_head: 10 + creeper_wall_head: 10 + crimson_button: 1 + crimson_door: 2 + crimson_fence: 2 + crimson_fence_gate: 4 + crimson_fungus: 1 + crimson_hyphae: 0 + crimson_nylium: 0 + crimson_planks: 1 + crimson_pressure_plate: 2 + crimson_roots: 0 + crimson_sign: 6 + crimson_slab: 1 + crimson_stairs: 2 + crimson_stem: 1 + crimson_trapdoor: 3 + crimson_wall_sign: 6 + crying_obsidian: 15 + cut_red_sandstone: 2 + cut_red_sandstone_slab: 1 + cut_sandstone: 2 + cut_sandstone_slab: 1 + cyan_banner: 2 + cyan_bed: 6 + cyan_carpet: 1 + cyan_concrete: 3 + cyan_concrete_powder: 2 + cyan_glazed_terracotta: 5 + cyan_shulker_box: 11 + cyan_stained_glass: 2 + cyan_stained_glass_pane: 1 + cyan_terracotta: 2 + cyan_wall_banner: 2 + cyan_wool: 2 + damaged_anvil: 5 + dandelion: 1 + dark_oak_button: 1 + dark_oak_door: 2 + dark_oak_fence: 2 + dark_oak_fence_gate: 4 + dark_oak_leaves: 0 + dark_oak_log: 0 + dark_oak_planks: 1 + dark_oak_pressure_plate: 2 + dark_oak_sapling: 0 + dark_oak_sign: 6 + dark_oak_slab: 1 + dark_oak_stairs: 2 + dark_oak_trapdoor: 3 + dark_oak_wall_sign: 6 + dark_oak_wood: 0 + dark_prismarine: 1 + dark_prismarine_slab: 1 + dark_prismarine_stairs: 2 + daylight_detector: 10 + dead_brain_coral: 1 + dead_brain_coral_block: 1 + dead_brain_coral_fan: 1 + dead_brain_coral_wall_fan: 1 + dead_bubble_coral: 1 + dead_bubble_coral_block: 1 + dead_bubble_coral_fan: 1 + dead_bubble_coral_wall_fan: 1 + dead_bush: 0 + dead_fire_coral: 1 + dead_fire_coral_block: 1 + dead_fire_coral_fan: 1 + dead_fire_coral_wall_fan: 1 + dead_horn_coral: 1 + dead_horn_coral_block: 1 + dead_horn_coral_fan: 1 + dead_horn_coral_wall_fan: 1 + dead_tube_coral: 1 + dead_tube_coral_block: 1 + dead_tube_coral_fan: 1 + dead_tube_coral_wall_fan: 1 + detector_rail: 10 + diamond_block: 300 + diamond_ore: 10 + diorite: 1 + diorite_slab: 1 + diorite_stairs: 1 + diorite_wall: 1 + dirt: 3 + dirt_path: 4 + dispenser: 5 + dragon_egg: 150 + dragon_head: 1 + dragon_wall_head: 10 + dried_kelp_block: 3 + dropper: 5 + emerald_block: 150 + emerald_ore: 10 + enchanting_table: 150 + end_gateway: 0 + end_portal: 0 + end_portal_frame: 0 + end_rod: 3 + end_stone: 1 + end_stone_brick_slab: 2 + end_stone_brick_stairs: 2 + end_stone_brick_wall: 2 + end_stone_bricks: 2 + ender_chest: 150 + farmland: 3 + fern: 0 + fire: 0 + fire_coral: 1 + fire_coral_block: 1 + fire_coral_fan: 1 + fire_coral_wall_fan: 1 + fletching_table: 8 + flower_pot: 2 + frosted_ice: 6 + furnace: 8 + gilded_blackstone: 5 + glass: 2 + glass_pane: 1 + glowstone: 1 + gold_block: 150 + gold_ore: 5 + granite: 1 + granite_slab: 3 + granite_stairs: 2 + granite_wall: 1 + short_grass: 4 + grass_block: 4 + gravel: 1 + gray_banner: 2 + gray_bed: 6 + gray_carpet: 1 + gray_concrete: 3 + gray_concrete_powder: 2 + gray_glazed_terracotta: 5 + gray_shulker_box: 11 + gray_stained_glass: 2 + gray_stained_glass_pane: 1 + gray_terracotta: 2 + gray_wall_banner: 2 + gray_wool: 2 + green_banner: 2 + green_bed: 6 + green_carpet: 1 + green_concrete: 3 + green_concrete_powder: 2 + green_glazed_terracotta: 5 + green_shulker_box: 11 + green_stained_glass: 2 + green_stained_glass_pane: 1 + green_terracotta: 2 + green_wall_banner: 2 + green_wool: 2 + grindstone: 8 + hay_block: 2 + heavy_weighted_pressure_plate: 2 + honey_block: 5 + honeycomb_block: 3 + hopper: -10 + horn_coral: 1 + horn_coral_block: 1 + horn_coral_fan: 1 + horn_coral_wall_fan: 1 + ice: 5 + infested_chiseled_stone_bricks: 2 + infested_cobblestone: 1 + infested_cracked_stone_bricks: 2 + infested_mossy_stone_bricks: 2 + infested_stone: 1 + infested_stone_bricks: 2 + iron_bars: 2 + iron_block: 10 + iron_door: 5 + iron_ore: 3 + iron_trapdoor: 4 + jack_o_lantern: 2 + jigsaw: 0 + jukebox: 10 + jungle_button: 1 + jungle_door: 2 + jungle_fence: 2 + jungle_fence_gate: 4 + jungle_leaves: 0 + jungle_log: 0 + jungle_planks: 1 + jungle_pressure_plate: 2 + jungle_sapling: 0 + jungle_sign: 6 + jungle_slab: 3 + jungle_stairs: 2 + jungle_trapdoor: 3 + jungle_wall_sign: 6 + jungle_wood: 0 + kelp: 0 + kelp_plant: 0 + ladder: 2 + lantern: 3 + lapis_block: 10 + lapis_ore: 3 + large_fern: 0 + lava: 0 + lectern: 8 + lever: 1 + light_blue_banner: 2 + light_blue_bed: 6 + light_blue_carpet: 1 + light_blue_concrete: 3 + light_blue_concrete_powder: 2 + light_blue_glazed_terracotta: 5 + light_blue_shulker_box: 11 + light_blue_stained_glass: 2 + light_blue_stained_glass_pane: 1 + light_blue_terracotta: 2 + light_blue_wall_banner: 2 + light_blue_wool: 2 + light_gray_banner: 2 + light_gray_bed: 6 + light_gray_carpet: 1 + light_gray_concrete: 3 + light_gray_concrete_powder: 2 + light_gray_glazed_terracotta: 5 + light_gray_shulker_box: 11 + light_gray_stained_glass: 2 + light_gray_stained_glass_pane: 1 + light_gray_terracotta: 2 + light_gray_wall_banner: 2 + light_gray_wool: 2 + light_weighted_pressure_plate: 3 + lilac: 1 + lily_of_the_valley: 1 + lily_pad: 5 + lime_banner: 2 + lime_bed: 6 + lime_carpet: 1 + lime_concrete: 3 + lime_concrete_powder: 2 + lime_glazed_terracotta: 5 + lime_shulker_box: 11 + lime_stained_glass: 2 + lime_stained_glass_pane: 1 + lime_terracotta: 2 + lime_wall_banner: 2 + lime_wool: 2 + lodestone: 10 + loom: 5 + magenta_banner: 2 + magenta_bed: 6 + magenta_carpet: 1 + magenta_concrete: 3 + magenta_concrete_powder: 2 + magenta_glazed_terracotta: 5 + magenta_shulker_box: 11 + magenta_stained_glass: 2 + magenta_stained_glass_pane: 1 + magenta_terracotta: 2 + magenta_wall_banner: 2 + magenta_wool: 2 + magma_block: 3 + melon: 0 + melon_stem: 0 + mossy_cobblestone: 0 + mossy_cobblestone_slab: 3 + mossy_cobblestone_stairs: 2 + mossy_cobblestone_wall: 1 + mossy_stone_brick_slab: 2 + mossy_stone_brick_stairs: 2 + mossy_stone_brick_wall: 2 + mossy_stone_bricks: 2 + moving_piston: 1 + mushroom_stem: 1 + mycelium: 5 + nether_brick_fence: 2 + nether_brick_slab: 3 + nether_brick_stairs: 2 + nether_brick_wall: 2 + nether_bricks: 2 + nether_gold_ore: 1 + nether_portal: 15 + nether_quartz_ore: 1 + nether_sprouts: 1 + nether_wart: 0 + nether_wart_block: 2 + netherite_block: 150 + netherrack: 0 + note_block: 10 + oak_button: 1 + oak_door: 2 + oak_fence: 2 + oak_fence_gate: 4 + oak_leaves: 0 + oak_log: 0 + oak_planks: 1 + oak_pressure_plate: 2 + oak_sapling: 0 + oak_sign: 6 + oak_slab: 3 + oak_stairs: 2 + oak_trapdoor: 3 + oak_wall_sign: 6 + oak_wood: 0 + observer: 3 + obsidian: 10 + orange_banner: 2 + orange_bed: 6 + orange_carpet: 1 + orange_concrete: 3 + orange_concrete_powder: 2 + orange_glazed_terracotta: 5 + orange_shulker_box: 11 + orange_stained_glass: 2 + orange_stained_glass_pane: 1 + orange_terracotta: 2 + orange_tulip: 1 + orange_wall_banner: 2 + orange_wool: 2 + oxeye_daisy: 1 + packed_ice: 5 + peony: 1 + petrified_oak_slab: 3 + pink_banner: 2 + pink_bed: 6 + pink_carpet: 1 + pink_concrete: 3 + pink_concrete_powder: 2 + pink_glazed_terracotta: 5 + pink_shulker_box: 11 + pink_stained_glass: 2 + pink_stained_glass_pane: 1 + pink_terracotta: 2 + pink_tulip: 1 + pink_wall_banner: 2 + pink_wool: 2 + piston: 2 + piston_head: 1 + player_head: 10 + player_wall_head: 10 + podzol: 2 + polished_andesite: 1 + polished_andesite_slab: 3 + polished_andesite_stairs: 2 + polished_basalt: 0 + polished_blackstone: 3 + polished_blackstone_brick_slab: 2 + polished_blackstone_brick_stairs: 2 + polished_blackstone_brick_wall: 2 + polished_blackstone_bricks: 2 + polished_blackstone_button: 1 + polished_blackstone_pressure_plate: 2 + polished_blackstone_slab: 3 + polished_blackstone_stairs: 2 + polished_blackstone_wall: 1 + polished_diorite: 3 + polished_diorite_slab: 3 + polished_diorite_stairs: 2 + polished_granite: 3 + polished_granite_slab: 3 + polished_granite_stairs: 2 + poppy: 1 + potatoes: 0 + potted_acacia_sapling: 2 + potted_allium: 2 + potted_azure_bluet: 2 + potted_bamboo: 2 + potted_birch_sapling: 2 + potted_blue_orchid: 2 + potted_brown_mushroom: 2 + potted_cactus: 2 + potted_cornflower: 2 + potted_crimson_fungus: 2 + potted_crimson_roots: 2 + potted_dandelion: 2 + potted_dark_oak_sapling: 2 + potted_dead_bush: 2 + potted_fern: 2 + potted_jungle_sapling: 2 + potted_lily_of_the_valley: 2 + potted_oak_sapling: 2 + potted_orange_tulip: 2 + potted_oxeye_daisy: 2 + potted_pink_tulip: 2 + potted_poppy: 2 + potted_red_mushroom: 2 + potted_red_tulip: 2 + potted_spruce_sapling: 2 + potted_warped_fungus: 2 + potted_warped_roots: 2 + potted_white_tulip: 2 + potted_wither_rose: 2 + powered_rail: 2 + prismarine: 1 + prismarine_brick_slab: 3 + prismarine_brick_stairs: 2 + prismarine_bricks: 2 + prismarine_slab: 3 + prismarine_stairs: 2 + prismarine_wall: 2 + pumpkin: 0 + pumpkin_stem: 0 + purple_banner: 2 + purple_bed: 6 + purple_carpet: 1 + purple_concrete: 3 + purple_concrete_powder: 2 + purple_glazed_terracotta: 5 + purple_shulker_box: 11 + purple_stained_glass: 2 + purple_stained_glass_pane: 1 + purple_terracotta: 2 + purple_wall_banner: 2 + purple_wool: 2 + purpur_block: 3 + purpur_pillar: 4 + purpur_slab: 3 + purpur_stairs: 2 + quartz_block: 4 + quartz_bricks: 2 + quartz_pillar: 4 + quartz_slab: 3 + quartz_stairs: 2 + rail: 7 + red_banner: 2 + red_bed: 6 + red_carpet: 1 + red_concrete: 3 + red_concrete_powder: 2 + red_glazed_terracotta: 5 + red_mushroom: 1 + red_mushroom_block: 1 + red_nether_brick_slab: 2 + red_nether_brick_stairs: 2 + red_nether_brick_wall: 2 + red_nether_bricks: 2 + red_sand: 1 + red_sandstone: 0 + red_sandstone_slab: 3 + red_sandstone_stairs: 2 + red_sandstone_wall: 2 + red_shulker_box: 11 + red_stained_glass: 2 + red_stained_glass_pane: 1 + red_terracotta: 2 + red_tulip: 1 + red_wall_banner: 2 + red_wool: 2 + redstone_block: 10 + redstone_lamp: 10 + redstone_ore: 1 + redstone_torch: 5 + redstone_wall_torch: 5 + redstone_wire: 1 + repeater: 6 + repeating_command_block: 0 + respawn_anchor: 100 + rose_bush: 1 + sand: 0 + sandstone: 0 + sandstone_slab: 1 + sandstone_stairs: 2 + sandstone_wall: 2 + scaffolding: 6 + sea_lantern: 9 + sea_pickle: 0 + seagrass: 0 + shroomlight: 1 + shulker_box: 10 + skeleton_skull: 10 + skeleton_wall_skull: 100 + slime_block: 10 + smithing_table: 6 + smoker: 10 + smooth_quartz: 4 + smooth_quartz_slab: 3 + smooth_quartz_stairs: 2 + smooth_red_sandstone: 4 + smooth_red_sandstone_slab: 3 + smooth_red_sandstone_stairs: 2 + smooth_sandstone: 4 + smooth_sandstone_slab: 3 + smooth_sandstone_stairs: 3 + smooth_stone: 0 + smooth_stone_slab: 3 + snow: 0 + snow_block: 0 + soul_campfire: 3 + soul_fire: 1 + soul_lantern: 3 + soul_sand: 2 + soul_soil: 1 + soul_torch: 1 + soul_wall_torch: 1 + spawner: 50 + sponge: 10 + spruce_button: 1 + spruce_door: 2 + spruce_fence: 2 + spruce_fence_gate: 4 + spruce_leaves: 0 + spruce_log: 0 + spruce_planks: 1 + spruce_pressure_plate: 2 + spruce_sapling: 0 + spruce_sign: 6 + spruce_slab: 3 + spruce_stairs: 2 + spruce_trapdoor: 3 + spruce_wall_sign: 6 + spruce_wood: 0 + sticky_piston: 1 + stone: 0 + stone_brick_slab: 3 + stone_brick_stairs: 2 + stone_brick_wall: 2 + stone_bricks: 2 + stone_button: 1 + stone_pressure_plate: 2 + stone_slab: 3 + stone_stairs: 2 + stonecutter: 4 + stripped_acacia_log: 0 + stripped_acacia_wood: 0 + stripped_birch_log: 0 + stripped_birch_wood: 0 + stripped_crimson_hyphae: 0 + stripped_crimson_stem: 0 + stripped_dark_oak_log: 0 + stripped_dark_oak_wood: 0 + stripped_jungle_log: 0 + stripped_jungle_wood: 0 + stripped_oak_log: 0 + stripped_oak_wood: 0 + stripped_spruce_log: 0 + stripped_spruce_wood: 0 + stripped_warped_hyphae: 0 + stripped_warped_stem: 0 + structure_block: 0 + structure_void: 0 + sugar_cane: 0 + sunflower: 0 + sweet_berry_bush: 0 + tall_grass: 0 + tall_seagrass: 0 + target: 5 + terracotta: 2 + tnt: 5 + torch: 2 + trapped_chest: 10 + tripwire: 2 + tripwire_hook: 2 + tube_coral: 0 + tube_coral_block: 0 + tube_coral_fan: 0 + tube_coral_wall_fan: 0 + turtle_egg: 10 + twisting_vines: 0 + twisting_vines_plant: 0 + vine: 0 + void_air: 0 + wall_torch: 2 + warped_button: 1 + warped_door: 3 + warped_fence: 2 + warped_fence_gate: 4 + warped_fungus: 0 + warped_hyphae: 0 + warped_nylium: 1 + warped_planks: 1 + warped_pressure_plate: 2 + warped_roots: 0 + warped_sign: 6 + warped_slab: 3 + warped_stairs: 2 + warped_stem: 0 + warped_trapdoor: 3 + warped_wall_sign: 6 + warped_wart_block: 1 + water: 0 + weeping_vines: 0 + weeping_vines_plant: 0 + wet_sponge: 10 + wheat: 0 + white_banner: 2 + white_bed: 6 + white_carpet: 1 + white_concrete: 3 + white_concrete_powder: 2 + white_glazed_terracotta: 5 + white_shulker_box: 11 + white_stained_glass: 2 + white_stained_glass_pane: 1 + white_terracotta: 2 + white_tulip: 1 + white_wall_banner: 2 + white_wool: 2 + wither_rose: 1 + wither_skeleton_skull: 10 + wither_skeleton_wall_skull: 10 + yellow_banner: 2 + yellow_bed: 6 + yellow_carpet: 1 + yellow_concrete: 3 + yellow_concrete_powder: 2 + yellow_glazed_terracotta: 5 + yellow_shulker_box: 11 + yellow_stained_glass: 2 + yellow_stained_glass_pane: 1 + yellow_terracotta: 2 + yellow_wall_banner: 2 + yellow_wool: 2 + zombie_head: 10 + zombie_wall_head: 10 + deepslate: 1 + cobbled_deepslate: 0 + polished_deepslate: 2 + calcite: 0 + tuff: 0 + tuff_slab: 3 + tuff_stairs: 2 + tuff_wall: 1 + chiseled_tuff: 1 + polished_tuff: 2 + polished_tuff_slab: 3 + polished_tuff_stairs: 2 + polished_tuff_wall: 1 + tuff_bricks: 2 + tuff_brick_slab: 3 + tuff_brick_stairs: 2 + tuff_brick_wall: 2 + chiseled_tuff_bricks: 1 + dripstone_block: 3 + rooted_dirt: 0 + mud: 0 + cherry_planks: 1 + pale_oak_planks: 1 + mangrove_planks: 1 + bamboo_planks: 1 + bamboo_mosaic: 1 + cherry_sapling: 0 + pale_oak_sapling: 0 + mangrove_propagule: 0 + suspicious_sand: 5 + suspicious_gravel: 5 + deepslate_coal_ore: 1 + deepslate_iron_ore: 1 + copper_ore: 1 + deepslate_copper_ore: 1 + deepslate_gold_ore: 1 + deepslate_redstone_ore: 1 + deepslate_emerald_ore: 1 + deepslate_lapis_ore: 1 + deepslate_diamond_ore: 1 + raw_iron_block: 10 + raw_copper_block: 10 + raw_gold_block: 10 + heavy_core: 1 + amethyst_block: 15 + budding_amethyst: 20 + copper_block: 9 + exposed_copper: 9 + weathered_copper: 9 + oxidized_copper: 9 + chiseled_copper: 9 + exposed_chiseled_copper: 9 + weathered_chiseled_copper: 9 + oxidized_chiseled_copper: 9 + cut_copper: 9 + exposed_cut_copper: 9 + weathered_cut_copper: 9 + oxidized_cut_copper: 9 + cut_copper_stairs: 2 + exposed_cut_copper_stairs: 2 + weathered_cut_copper_stairs: 0 + oxidized_cut_copper_stairs: 2 + cut_copper_slab: 3 + exposed_cut_copper_slab: 3 + weathered_cut_copper_slab: 3 + oxidized_cut_copper_slab: 3 + waxed_copper_block: 9 + waxed_exposed_copper: 9 + waxed_weathered_copper: 9 + waxed_oxidized_copper: 9 + waxed_chiseled_copper: 9 + waxed_exposed_chiseled_copper: 9 + waxed_weathered_chiseled_copper: 0 + waxed_oxidized_chiseled_copper: 9 + waxed_cut_copper: 9 + waxed_exposed_cut_copper: 9 + waxed_weathered_cut_copper: 9 + waxed_oxidized_cut_copper: 9 + waxed_cut_copper_stairs: 2 + waxed_exposed_cut_copper_stairs: 2 + waxed_weathered_cut_copper_stairs: 0 + waxed_oxidized_cut_copper_stairs: 2 + waxed_cut_copper_slab: 3 + waxed_exposed_cut_copper_slab: 3 + waxed_weathered_cut_copper_slab: 0 + waxed_oxidized_cut_copper_slab: 3 + cherry_log: 0 + pale_oak_log: 0 + mangrove_log: 0 + mangrove_roots: 0 + muddy_mangrove_roots: 0 + bamboo_block: 1 + stripped_cherry_log: 0 + stripped_pale_oak_log: 0 + stripped_mangrove_log: 0 + stripped_cherry_wood: 0 + stripped_pale_oak_wood: 0 + stripped_mangrove_wood: 0 + stripped_bamboo_block: 0 + cherry_wood: 0 + pale_oak_wood: 0 + mangrove_wood: 0 + cherry_leaves: 0 + pale_oak_leaves: 0 + mangrove_leaves: 0 + azalea_leaves: 0 + flowering_azalea_leaves: 0 + tinted_glass: 3 + azalea: 0 + flowering_azalea: 0 + open_eyeblossom: 0 + closed_eyeblossom: 0 + torchflower: 0 + pitcher_plant: 0 + spore_blossom: 0 + pink_petals: 0 + moss_carpet: 0 + moss_block: 0 + pale_moss_carpet: 0 + pale_hanging_moss: 0 + pale_moss_block: 0 + hanging_roots: 0 + big_dripleaf: 0 + small_dripleaf: 0 + cherry_slab: 3 + pale_oak_slab: 3 + mangrove_slab: 3 + bamboo_slab: 3 + bamboo_mosaic_slab: 3 + mud_brick_slab: 3 + chiseled_bookshelf: 3 + decorated_pot: 2 + creaking_heart: 1 + cherry_fence: 2 + pale_oak_fence: 2 + mangrove_fence: 2 + bamboo_fence: 2 + smooth_basalt: 0 + infested_deepslate: 0 + packed_mud: 0 + mud_bricks: 2 + deepslate_bricks: 2 + cracked_deepslate_bricks: 1 + deepslate_tiles: 2 + cracked_deepslate_tiles: 1 + chiseled_deepslate: 2 + reinforced_deepslate: 10 + glow_lichen: 0 + resin_clump: 0 + resin_block: 0 + resin_bricks: 0 + resin_brick_stairs: 2 + resin_brick_slab: 3 + resin_brick_wall: 1 + chiseled_resin_bricks: 1 + mud_brick_stairs: 2 + sculk: 0 + sculk_vein: 0 + sculk_catalyst: 5 + sculk_shrieker: 5 + cherry_stairs: 2 + pale_oak_stairs: 2 + mangrove_stairs: 2 + bamboo_stairs: 2 + bamboo_mosaic_stairs: 2 + mud_brick_wall: 1 + cobbled_deepslate_wall: 1 + polished_deepslate_wall: 2 + deepslate_brick_wall: 1 + deepslate_tile_wall: 1 + light: 0 + sniffer_egg: 10 + cobbled_deepslate_stairs: 2 + polished_deepslate_stairs: 2 + deepslate_brick_stairs: 2 + deepslate_tile_stairs: 2 + cobbled_deepslate_slab: 3 + polished_deepslate_slab: 3 + deepslate_brick_slab: 3 + deepslate_tile_slab: 3 + lightning_rod: 3 + sculk_sensor: 3 + calibrated_sculk_sensor: 3 + cherry_button: 1 + pale_oak_button: 1 + mangrove_button: 1 + bamboo_button: 1 + cherry_pressure_plate: 2 + pale_oak_pressure_plate: 2 + mangrove_pressure_plate: 2 + bamboo_pressure_plate: 2 + cherry_door: 2 + pale_oak_door: 2 + mangrove_door: 2 + bamboo_door: 2 + copper_door: 2 + exposed_copper_door: 2 + weathered_copper_door: 2 + oxidized_copper_door: 2 + waxed_copper_door: 2 + waxed_exposed_copper_door: 2 + waxed_weathered_copper_door: 0 + waxed_oxidized_copper_door: 2 + cherry_trapdoor: 2 + pale_oak_trapdoor: 2 + mangrove_trapdoor: 2 + bamboo_trapdoor: 2 + copper_trapdoor: 2 + exposed_copper_trapdoor: 2 + weathered_copper_trapdoor: 2 + oxidized_copper_trapdoor: 2 + waxed_copper_trapdoor: 2 + waxed_exposed_copper_trapdoor: 2 + waxed_weathered_copper_trapdoor: 0 + waxed_oxidized_copper_trapdoor: 2 + cherry_fence_gate: 2 + pale_oak_fence_gate: 2 + mangrove_fence_gate: 2 + bamboo_fence_gate: 2 + cherry_sign: 6 + pale_oak_sign: 6 + mangrove_sign: 6 + bamboo_sign: 6 + oak_hanging_sign: 6 + spruce_hanging_sign: 6 + birch_hanging_sign: 6 + jungle_hanging_sign: 6 + acacia_hanging_sign: 6 + cherry_hanging_sign: 6 + dark_oak_hanging_sign: 6 + pale_oak_hanging_sign: 6 + mangrove_hanging_sign: 6 + bamboo_hanging_sign: 6 + crimson_hanging_sign: 6 + warped_hanging_sign: 6 + crafter: 1 + piglin_head: 10 + bee_nest: 0 + beehive: 0 + candle: 1 + white_candle: 1 + orange_candle: 1 + magenta_candle: 1 + light_blue_candle: 1 + yellow_candle: 1 + lime_candle: 1 + pink_candle: 1 + gray_candle: 1 + light_gray_candle: 1 + cyan_candle: 1 + purple_candle: 1 + blue_candle: 1 + brown_candle: 1 + green_candle: 1 + red_candle: 1 + black_candle: 1 + small_amethyst_bud: 0 + medium_amethyst_bud: 0 + large_amethyst_bud: 0 + amethyst_cluster: 0 + pointed_dripstone: 0 + ochre_froglight: 5 + verdant_froglight: 5 + pearlescent_froglight: 5 + frogspawn: 10 + copper_grate: 9 + exposed_copper_grate: 9 + weathered_copper_grate: 9 + oxidized_copper_grate: 9 + waxed_copper_grate: 9 + waxed_exposed_copper_grate: 9 + waxed_weathered_copper_grate: 0 + waxed_oxidized_copper_grate: 9 + copper_bulb: 9 + exposed_copper_bulb: 9 + weathered_copper_bulb: 9 + oxidized_copper_bulb: 9 + waxed_copper_bulb: 9 + waxed_exposed_copper_bulb: 9 + waxed_weathered_copper_bulb: 0 + waxed_oxidized_copper_bulb: 9 + trial_spawner: 50 + vault: 1 + cherry_wall_sign: 6 + pale_oak_wall_sign: 6 + mangrove_wall_sign: 6 + bamboo_wall_sign: 6 + oak_wall_hanging_sign: 6 + spruce_wall_hanging_sign: 6 + birch_wall_hanging_sign: 6 + acacia_wall_hanging_sign: 6 + cherry_wall_hanging_sign: 6 + jungle_wall_hanging_sign: 6 + dark_oak_wall_hanging_sign: 6 + pale_oak_wall_hanging_sign: 6 + mangrove_wall_hanging_sign: 6 + crimson_wall_hanging_sign: 6 + warped_wall_hanging_sign: 6 + bamboo_wall_hanging_sign: 6 + water_cauldron: 0 + lava_cauldron: 0 + powder_snow_cauldron: 0 + potted_torchflower: 2 + potted_cherry_sapling: 2 + potted_pale_oak_sapling: 2 + potted_mangrove_propagule: 2 + piglin_wall_head: 10 + torchflower_crop: 0 + pitcher_crop: 0 + candle_cake: 1 + white_candle_cake: 1 + orange_candle_cake: 1 + magenta_candle_cake: 1 + light_blue_candle_cake: 1 + yellow_candle_cake: 1 + lime_candle_cake: 1 + pink_candle_cake: 1 + gray_candle_cake: 1 + light_gray_candle_cake: 1 + cyan_candle_cake: 1 + purple_candle_cake: 1 + blue_candle_cake: 1 + brown_candle_cake: 1 + green_candle_cake: 1 + red_candle_cake: 1 + black_candle_cake: 1 + powder_snow: 0 + cave_vines: 0 + cave_vines_plant: 0 + big_dripleaf_stem: 0 + potted_azalea_bush: 2 + potted_flowering_azalea_bush: 2 + potted_open_eyeblossom: 2 + potted_closed_eyeblossom: 2 + armadillo_spawner: 50 + allay_spawner: 50 + axolotl_spawner: 50 + bat_spawner: 50 + bee_spawner: 50 + blaze_spawner: 50 + bogged_spawner: 50 + breeze_spawner: 50 + cat_spawner: 50 + camel_spawner: 50 + cave_spider_spawner: 50 + chicken_spawner: 50 + cod_spawner: 50 + cow_spawner: 50 + creeper_spawner: 50 + dolphin_spawner: 50 + donkey_spawner: 50 + drowned_spawner: 50 + elder_guardian_spawner: 50 + ender_dragon_spawner: 50 + enderman_spawner: 50 + endermite_spawner: 50 + evoker_spawner: 50 + fox_spawner: 50 + frog_spawner: 50 + ghast_spawner: 50 + glow_squid_spawner: 50 + goat_spawner: 50 + guardian_spawner: 50 + hoglin_spawner: 50 + horse_spawner: 50 + husk_spawner: 50 + iron_golem_spawner: 50 + llama_spawner: 50 + magma_cube_spawner: 50 + mooshroom_spawner: 50 + mule_spawner: 50 + ocelot_spawner: 50 + panda_spawner: 50 + parrot_spawner: 50 + phantom_spawner: 50 + pig_spawner: 50 + piglin_spawner: 50 + piglin_brute_spawner: 50 + pillager_spawner: 50 + polar_bear_spawner: 50 + pufferfish_spawner: 50 + rabbit_spawner: 50 + ravager_spawner: 50 + salmon_spawner: 50 + sheep_spawner: 50 + shulker_spawner: 50 + silverfish_spawner: 50 + skeleton_spawner: 50 + skeleton_horse_spawner: 50 + slime_spawner: 50 + sniffer_spawner: 50 + snow_golem_spawner: 50 + spider_spawner: 50 + squid_spawner: 50 + stray_spawner: 50 + strider_spawner: 50 + tadpole_spawner: 50 + trader_llama_spawner: 50 + tropical_fish_spawner: 50 + turtle_spawner: 50 + vex_spawner: 50 + villager_spawner: 50 + vindicator_spawner: 50 + wandering_trader_spawner: 50 + warden_spawner: 50 + witch_spawner: 50 + wither_spawner: 50 + wither_skeleton_spawner: 50 + wolf_spawner: 50 + zoglin_spawner: 50 + creaking_spawner: 50 + zombie_spawner: 50 + zombie_horse_spawner: 50 + zombie_villager_spawner: 50 + zombified_piglin_spawner: 50 + cracked_nether_bricks: 1 + cracked_polished_blackstone_bricks: 1 worlds: caveblock-world: - STONE: 0 - GRANITE: 0 - ANDESITE: 0 - DIORITE: 0 + stone: 0 + granite: 0 + andesite: 0 + diorite: 0 acidisland_world: - BRAIN_CORAL: 0 - BRAIN_CORAL_BLOCK: 0 - BRAIN_CORAL_FAN: 0 - BRAIN_CORAL_WALL_FAN: 0 - BUBBLE_CORAL: 0 - BUBBLE_CORAL_BLOCK: 0 - BUBBLE_CORAL_FAN: 0 - BUBBLE_CORAL_WALL_FAN: 0 - DEAD_BRAIN_CORAL: 0 - DEAD_BRAIN_CORAL_BLOCK: 0 - DEAD_BRAIN_CORAL_FAN: 0 - DEAD_BRAIN_CORAL_WALL_FAN: 0 - DEAD_BUBBLE_CORAL: 0 - DEAD_BUBBLE_CORAL_BLOCK: 0 - DEAD_BUBBLE_CORAL_FAN: 0 - DEAD_BUBBLE_CORAL_WALL_FAN: 0 - FIRE_CORAL: 0 - FIRE_CORAL_BLOCK: 0 - FIRE_CORAL_FAN: 0 - FIRE_CORAL_WALL_FAN: 0 - DEAD_FIRE_CORAL: 0 - DEAD_FIRE_CORAL_BLOCK: 0 - DEAD_FIRE_CORAL_FAN: 0 - DEAD_FIRE_CORAL_WALL_FAN: 0 - HORN_CORAL: 0 - HORN_CORAL_BLOCK: 0 - HORN_CORAL_FAN: 0 - HORN_CORAL_WALL_FAN: 0 - DEAD_HORN_CORAL: 0 - DEAD_HORN_CORAL_BLOCK: 0 - DEAD_HORN_CORAL_FAN: 0 - DEAD_HORN_CORAL_WALL_FAN: 0 - TUBE_CORAL: 0 - TUBE_CORAL_BLOCK: 0 - TUBE_CORAL_FAN: 0 - TUBE_CORAL_WALL_FAN: 0 - DEAD_TUBE_CORAL: 0 - DEAD_TUBE_CORAL_BLOCK: 0 - DEAD_TUBE_CORAL_FAN: 0 - DEAD_TUBE_CORAL_WALL_FAN: 0 - SAND: 0 - SANDSTONE: 0 - RED_SAND: 0 - ICE: 0 - AMETHYST_CLUSTER: 0 - AMETHYST_BLOCK: 0 - LARGE_AMETHYST_BUD: 0 - MEDIUM_AMETHYST_BUD: 0 - SMALL_AMETHYST_BUD: 0 - BUDDING_AMETHYST: 0 - SEA_PICKLE: 0 - CALCITE: 0 - TALL_SEAGRASS: 0 - SEAGRASS: 0 - SMOOTH_BASALT: 0 + brain_coral: 0 + brain_coral_block: 0 + brain_coral_fan: 0 + brain_coral_wall_fan: 0 + bubble_coral: 0 + bubble_coral_block: 0 + bubble_coral_fan: 0 + bubble_coral_wall_fan: 0 + dead_brain_coral: 0 + dead_brain_coral_block: 0 + dead_brain_coral_fan: 0 + dead_brain_coral_wall_fan: 0 + dead_bubble_coral: 0 + dead_bubble_coral_block: 0 + dead_bubble_coral_fan: 0 + dead_bubble_coral_wall_fan: 0 + fire_coral: 0 + fire_coral_block: 0 + fire_coral_fan: 0 + fire_coral_wall_fan: 0 + dead_fire_coral: 0 + dead_fire_coral_block: 0 + dead_fire_coral_fan: 0 + dead_fire_coral_wall_fan: 0 + horn_coral: 0 + horn_coral_block: 0 + horn_coral_fan: 0 + horn_coral_wall_fan: 0 + dead_horn_coral: 0 + dead_horn_coral_block: 0 + dead_horn_coral_fan: 0 + dead_horn_coral_wall_fan: 0 + tube_coral: 0 + tube_coral_block: 0 + tube_coral_fan: 0 + tube_coral_wall_fan: 0 + dead_tube_coral: 0 + dead_tube_coral_block: 0 + dead_tube_coral_fan: 0 + dead_tube_coral_wall_fan: 0 + sand: 0 + sandstone: 0 + red_sand: 0 + ice: 0 + amethyst_cluster: 0 + amethyst_block: 0 + large_amethyst_bud: 0 + medium_amethyst_bud: 0 + small_amethyst_bud: 0 + budding_amethyst: 0 + sea_pickle: 0 + calcite: 0 + tall_seagrass: 0 + seagrass: 0 + smooth_basalt: 0 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5876c35..5a3b5e3 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: BentoBox-Level main: world.bentobox.level.LevelPladdon version: ${project.version}${build.number} -api-version: "1.21" +api-version: "1.21.4" authors: [tastybento] contributors: ["The BentoBoxWorld Community"] diff --git a/src/test/java/world/bentobox/level/LevelTest.java b/src/test/java/world/bentobox/level/LevelTest.java index bce1d53..8ae4f4b 100644 --- a/src/test/java/world/bentobox/level/LevelTest.java +++ b/src/test/java/world/bentobox/level/LevelTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -55,6 +56,7 @@ import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType; import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.bentobox.managers.AddonsManager; import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.FlagsManager; @@ -74,7 +76,7 @@ */ @SuppressWarnings("deprecation") @RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, BentoBox.class, User.class, Util.class }) +@PrepareForTest({ Bukkit.class, BentoBox.class, User.class, Util.class, ItemsAdderHook.class }) public class LevelTest { private static File jFile; @@ -158,7 +160,9 @@ public void setUp() throws Exception { when(plugin.getSettings()).thenReturn(pluginSettings); when(pluginSettings.getDatabaseType()).thenReturn(value); - // when(plugin.isEnabled()).thenReturn(true); + // ItemsAdderHook + PowerMockito.mockStatic(ItemsAdderHook.class, Mockito.RETURNS_MOCKS); + when(ItemsAdderHook.isInRegistry(anyString())).thenReturn(true); // Command manager CommandsManager cm = mock(CommandsManager.class); when(plugin.getCommandsManager()).thenReturn(cm); @@ -272,12 +276,11 @@ private static void deleteAll(File file) throws IOException { } /** - * Test method for {@link world.bentobox.level.Level#onEnable()}. - */ + * Test method for {@link world.bentobox.level.Level#allLoaded() + */ @Test - public void testOnEnable() { - addon.onEnable(); - verify(plugin).logWarning("[Level] Level Addon: No such world in blockconfig.yml : acidisland_world"); + public void testAllLoaded() { + addon.allLoaded(); verify(plugin).log("[Level] Level hooking into BSkyBlock"); verify(cmd, times(3)).getAddon(); // 3 commands verify(adminCmd, times(5)).getAddon(); // Five commands @@ -292,6 +295,9 @@ public void testOnEnable() { // Commands verify(am).registerListener(eq(addon), any(IslandActivitiesListeners.class)); verify(am).registerListener(eq(addon), any(JoinLeaveListener.class)); + + verify(plugin).log("[Level] Level Addon: No such world in blockconfig.yml : acidisland_world"); + } /**